深拷贝和浅拷贝的区别
先看官方文档的说明
Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象.
b = copy.copy(a)
返回 a 的浅层复制
c = copy.deepcopy(a)
返回 a 的深层复制
浅层与深层复制的区别仅与复合对象相关。(包含列表或类的实例的等其他对象的对象)
- 浅层复制:构造一个新的复合对象,然后在尽可能的范围内将原始的对象中找到的对象引用插入其中
- 深层复制 构造一个新的复合对象,然后,递归地将在原始对象里找到的对象的副本插入其中
个人理解释义
-
第一点说明了 普通的赋值操作是 只是增加了一个新的引用,如图
-
第二点说明了 只有复合对象的深拷贝和浅拷贝的区别:
-
相同点:
- 他们都是创建了新的对象
- 将非复合对象进行副本插入
如图:在修改原来非复合对象时,不同拷贝后的值是不会变化的
-
不同点:
- 浅拷贝:将复合对象的引用插入其中,简单说就是指向原来的对象
- 深拷贝:将复合对象的副本插入其中,简单说就是复制了新的对象
如图:
-
总结:当有复合对象时,才能看出深拷贝和浅拷贝的区别,无复合对象时,是没有区别的。
常见问题
由于深拷贝是递归查找,因此会出现两个问题:
1是本身就是递归对象,会发生递归循环。
2是深拷贝会复制所有的内容,会导致过多的复制(将本该共享的内容也进行复制)。
解决方法
- 解决第一个问题办法是,进行记录,使用memo字段来记录已经复制的对象
- 解决第二个问题办法是,允许用户自己的类重载复制操作。
想要为一个类定义它自己的拷贝操作实现,可以通过定义特殊方法 copy() 和 deepcopy()。 调用前者以实现浅层拷贝操作;该方法不必传入额外参数。 调用后者以实现深层拷贝操作;它应转入一个参数,即 memo 字典。 如果 deepcopy() 实现需要创建一个组件的深层拷贝,它应当调用 deepcopy() 函数并以该组件作为第一个参数而以该 memo 字典作为第二个参数。。 memo 字典应当被当作不透明对象来处理
小窍门:官方文档推荐:
- 字典的浅拷贝使用dict.cppy()
- 列表的浅拷贝使用切片 copied_list = copied_list[:]