Python 浅复制与深复制(Shallow Copy & Deep Copy)

本文介绍了Python中赋值语句的引用机制,区分了浅复制和深复制的区别,以及Python对不可变对象的特殊处理。通过示例说明了如何避免浅复制带来的对象间影响,以及在类设计中的注意事项。
摘要由CSDN通过智能技术生成

在Python中,赋值语句的意义是在对象与变量之间建立引用关系,相当于给对象起了名字。对于复合类型对象,由于其可以保存其他类型对象的引用,而在复制时即引出了“仅复制引用关系”或“同时复制引用对象”两种选择,即浅复制和深复制。

一、浅复制示例

Python中的赋值语句是建立对象与变量名的引用关系,下面语句即是将list1与列表对象建立引用关系:

list1 = ['abc']

在这里插入图片描述
而对于集合类型的对象,其中元素保存的可能又是到其他对象的引用,下面语句中,list1保存了3个对象,其中列表和元组是引用,指向其实际对象:

list1 = ['abc', [1,2], (3,4)]

在这里插入图片描述
对于list1,当对其进行复制时,就有了浅复制和深复制两种选择。默认的构造函数或切片采用的都是浅复制。下面代码中,list2是list1的浅复制副本(副本共享内部对象的引用):

list1 = ['abc', [1,2], (3,4)]
list2 = list1[:] 或list2 = list(list1)

在这里插入图片描述
改变list2中列表的元素,list1中的列表也改变了,可以证明它们引用的是相同的对象:

list2[1].append(3)
list1[1]

在这里插入图片描述
对象引用关系如下:
在这里插入图片描述

二、深复制示例

有时我们需要对象的深复制,即集合内部对象不共享引用。利用copy模块的deepcopy()函数可以为任意对象做深复制(其还有个copy()函数可以做任意对象的浅复制)。

下面是list1的深复制引用关系图,从结果来看,list1和list2中的列表已经独立复制了,为什么元组还是指向同一个对象?这其实是python内部的一个优化机制:

import copy
list1 = ['abc', [1,2], (3,4)]
list2 = copy.deepcopy(list1)

在这里插入图片描述
我们先测试一下变更list2中的列表和元组对象,可以发现list1和list2已经互不影响了:

list2[1].append(3)
list2[2] += (5,6)

在这里插入图片描述

2.1 python对不可变对象的优化

上面的例子中,我们对list2[2]的元组对象做+=操作,这个应该做原地变更,但由于元组是不可变对象,所以python会重新创建一个元组,然后重新绑定至list2[2]的引用上,从结果上来看,深复制对于不可以用对象依然复制引用关系并不会造成复制对象间的相互影响。
在这里插入图片描述
在深复制时,我们期望的是python会复制所有引用对象,而不仅仅是引用关系,但它会欺骗你。对于不可变对象python依然会复制引用关系,这其实是一种优化,防止重复创建对象。这在普通的常量上也可以体现,下面示例创建了2个变量a,b都等于1,但实际上python只创建了1个数字对象,然后让a,b都指向它(通过id()函数和is可以确定a,b指向的是同一个对象):

a = 1
b = 1
id(a), id(b)
a is b

在这里插入图片描述

可以总结出:浅复制可能会造成复制对象间的相互影响,有时你可以利用这种影响传递变化,但有时也可能造成意想不到的影响,特别是在类编写中,尽量避免用可变对象作为初始化参数,其可能造成实例之间的互相干扰。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,拷贝指的是创建一个新的对象,包含原始对象的所有内容。但是,拷贝和拷贝会根据拷贝方式的不同,影响拷贝结果。 拷贝(Deep Copy)是指创建一个新的对象,包含原始对象的所有内容,甚至包括原始对象中引用的对象。也就是说,拷贝会递归地复制所有对象,包括它们的内部对象。拷贝的结果是两个完全独立的对象,修改一个对象不会影响另一个对象。 拷贝(Shallow Copy)是指创建一个新的对象,包含原始对象的所有内容,但不会递归复制原始对象中引用的对象。也就是说,拷贝只复制对象的顶层内容,而不会对其内部对象进行复制拷贝的结果是两个对象共享同一个内部对象,修改一个对象会影响另一个对象。 下面是一个例子,可以更好地说明拷贝和拷贝的区别: ```python import copy # 定义一个列表 a = [1, 2, [3, 4]] # 拷贝 b = copy.copy(a) # 拷贝 c = copy.deepcopy(a) # 修改a的第二个元素 a[1] = 5 # 修改a的第三个元素中的第一个元素 a[2][0] = 6 # 输出a、b、c的值 print(a) # [1, 5, [6, 4]] print(b) # [1, 2, [6, 4]] print(c) # [1, 2, [3, 4]] ``` 在上面的例子中,我们先定义了一个列表a,它包含了一个嵌套列表。我们使用copy.copy()和copy.deepcopy()对a进行拷贝,并修改原始列表a的值。最后,我们输出了三个列表的值,可以看到,拷贝b的第三个元素的值也被修改了,而拷贝c的值没有受到影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值