While reading up the documentation for dict.copy(), it says that it makes a shallow copy of the dictionary. Same goes for the book I am following (Beazley’s Python Reference), which says:
The m.copy() method makes a shallow
copy of the items contained in a
mapping object and places them in a
new mapping object.
Consider this:
>>> original = dict(a=1, b=2)
>>> new = original.copy()
>>> new.update({'c': 3})
>>> original
{'a': 1, 'b': 2}
>>> new
{'a': 1, 'c': 3, 'b': 2}
So I assumed this would update the value of original (and add ‘c’: 3) also since I was doing a shallow copy. Like if you do it for a list:
>>> original = [1, 2, 3]
>>> new = original
>>> new.append(4)
>>> new, original
([1, 2, 3, 4], [1, 2, 3, 4])
This works as expected.
Since both are shallow copies, why is that the dict.copy() doesn’t work as I expect it to? Or my understanding of shallow vs deep copying is flawed?
回答 0
“浅复制”表示字典的内容不是按值复制,而只是创建一个新引用。
>>> a ={1:[1,2,3]}>>> b = a.copy()>>> a, b
({1:[1,2,3]},{1:[1,2,3]})>>> a[1].append(4)>>> a, b
({1:[1,2,3,4]},{1:[1,2,3,4]})
相反,深层副本将按值复制所有内容。
>>>import copy
>>> c = copy.deepcopy(a)>>> a, c
({1:[1,2,3,4]},{1:[1,2,3,4]})>>> a[1].append(5)>>> a, c
({1:[1,2,3,4,5]},{1:[1,2,3,4]})
It’s not a matter of deep copy or shallow copy, none of what you’re doing is deep copy.
Here:
>>> new = original
you’re creating a new reference to the the list/dict referenced by original.
while here:
>>> new = original.copy()
>>> # or
>>> new = list(original) # dict(original)
you’re creating a new list/dict which is filled with a copy of the references of objects contained in the original container.
回答 2
举个例子:
original = dict(a=1, b=2, c=dict(d=4, e=5))
new = original.copy()
现在,让我们在“浅”(第一)级别中更改一个值:
new['a']=10# new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}}# original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}}# no change in original, since ['a'] is an immutable integer
现在让我们将值更深一级地更改:
new['c']['d']=40# new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}}# original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}}# new['c'] points to the same original['d'] mutable dictionary, so it will be changed
original = dict(a=1, b=2, c=dict(d=4, e=5))
new = original.copy()
Now let’s change a value in the ‘shallow’ (first) level:
new['a'] = 10
# new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}}
# no change in original, since ['a'] is an immutable integer
Now let’s change a value one level deeper:
new['c']['d'] = 40
# new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}}
# new['c'] points to the same original['d'] mutable dictionary, so it will be changed
Adding to kennytm’s answer. When you do a shallow copy parent.copy() a new dictionary is created with same keys,but the values are not copied they are referenced.If you add a new value to parent_copy it won’t effect parent because parent_copy is a new dictionary not reference.
The hash(id) value of parent[1], parent_copy[1] are identical which implies [1,2,3] of parent[1] and parent_copy[1] stored at id 140690938288400.
But hash of parent and parent_copy are different which implies
They are different dictionaries and parent_copy is a new dictionary having values reference to values of parent
So if the original dict contains a list or another dictionary, modifying one them in the original or its shallow copy will modify them (the list or the dict) in the other.