理解dict.copy() - shadow 还是 deep?

Posted on 2015-3-11 in Code

最近在重新设计一段代码的时候,发现有一行使用dict.copy()的方式复制一个字典,第一反应是会和list一样,对新dict的任何操作都会影响原有的dict,结果实验了一下并不是这样。

>>> a = {'a':111, 'b':222}
>>> b = a.copy()
>>> b['c'] = 333
>>> del b['a']
>>> print a
>>> {'a': 111, 'b': 222}
>>> print b
>>> {'c': 333, 'b': 222}

这让我很困惑,为什么浅复制(shadow copy)的情况和list不一样。。。

StackOverflow上找到了一个回答,解答了我的疑惑,大致描述一下:

对于浅复制,意味着字典的内容不是对值的拷贝,而是创建了新的引用:

>>> a = {1: [1,2,3]}
>>> b = a.copy()
>>> print a, b
>>> ({1: [1, 2, 3]}, {1: [1, 2, 3]})
>>> a[1].append(4)
>>> print a, b
>>> ({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})

相对的,深复制(deep copy)会复制所有的内容,包括值:

>>> c = copy.deepcopy(a)
>>> print a, c
>>> ({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
>>> a[1].append(5)
>>> print a, c
>>> ({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})

总的来说:

1.a = b:引用复制,使a和b指向相同的对象:

a ---,
     v
     {1: L}
     ^   |
b ---'   '----> [1,2,3]

2.a = b.copy():浅复制,a和b会成为两个不同的对象,但它们的内容会共享相同的引用:

a ---> {1: L}
           |             
           >---> [1,2,3]
           |
b ---> {1: M}

3.a = copy.deepcopy(b):深复制,a、b的结构和内容都完全隔离开了:

a ---> {1: L}
           ‘-----> [1,2,3]
b ---> {1: M}
           ‘-----> [1,2,3]