春江暮客

春江暮客的个人学习分享网站

python里shallow copy和deepcopy的区别

2018-12-29 技术
python里shallow copy和deepcopy的区别

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

《python里shadowcopy和deepcopy的区别》

赋值(=)、浅拷贝(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 会更稳妥;但它也更耗内存和时间,所以在大对象上不要无脑使用。

友情链接

其它