python里shallow copy和deepcopy的区别
2018-12-29
技术
python 中经常需要拷贝对象,而很多“改了一个变量,另一个也跟着变”的 bug,本质上都和没有分清这三种操作有关:赋值、浅拷贝、深拷贝。

赋值(=)、浅拷贝(copy) 和深拷贝(deepcopy) 中,最容易混淆的通常不是赋值和拷贝,而是浅拷贝与深拷贝到底会不会共享内部子对象。
赋值语句并不会复制对象,它只是让两个变量同时指向同一个对象。这样一来,对其中一个变量看到的内容做修改,另一个变量也会看到同样的变化。
浅拷贝会复制最外层对象,但内部嵌套的可变对象仍然可能共享;深拷贝则会递归复制内部对象,因此通常更独立。
可以先记一个非常实用的判断规则:
- 只想要一个新变量名,还是操作同一份数据,用赋值
- 只需要复制外层容器,内部对象共享也可以,用浅拷贝
- 需要连内部嵌套列表、字典也一起隔离,用深拷贝
下面以实际代码说明三者区别
代码
from copy import deepcopy
dic1 = {'a': 2, 'b': 3, 'c': 4}
dic2=dic1
dic1["a"]=1
print(dic1)
#{'a': 1, 'b': 3, 'c': 4}
print(dic2)
#{'a': 1, 'b': 3, 'c': 4}
#赋值语句,两者完全一样,同时改变
dic1 = {'a': [1,2,3], 'b': 3, 'c': 4}
dic2 = dic1.copy()
dic1["a"] = [2,3,4]
print(dic1)
#{'a': [2, 3, 4], 'b': 3, 'c': 4}
print(dic2)
#{'a': [1, 2, 3], 'b': 3, 'c': 4}
###改变值不会影响另一个对象的值
dic1 = {'a': [1,2,3], 'b': 3, 'c': 4}
dic2 = dic1.copy()
dic1["a"].append(4)
print(dic1)
#{'a': [1, 2, 3, 4], 'b': 3, 'c': 4}
print(dic2)
#{'a': [1, 2, 3, 4], 'b': 3, 'c': 4}
###由此可见浅拷贝拷贝的是元素和元素引用的对象,如果其子对象是可变的,那么两个对象会同时改变,可参考https://docs.python.org/3/library/copy.html
dic1 = {'a': [1,2,3], 'b': 3, 'c': 4}
dic2 = deepcopy(dic1)
dic1["a"].append(4)
print(dic1)
#{'a': [1, 2, 3, 4], 'b': 3, 'c': 4}
print(dic2)
#{'a': [1, 2, 3], 'b': 3, 'c': 4}
总结
在实际应用中,如果你想“复制一份对象”,赋值语句通常不是正确选择,因为它只是额外创建了一个引用。
如果数据结构里有嵌套列表、嵌套字典,且你明确不希望相互影响,deepcopy 会更稳妥;但它也更耗内存和时间,所以在大对象上不要无脑使用。
- 原文作者:春江暮客
- 原文链接:https://www.bobobk.com/200.html
- 版权声明:本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。