Understanding dict.copy() - shallow or deep?
在阅读
The m.copy() method makes a shallow
copy of the items contained in a
mapping object and places them in a
new mapping object.
考虑一下:
1 2 3 4 5 6 7 | >>> 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} |
所以我假设这会更新
1 2 3 4 5 | >>> original = [1, 2, 3] >>> new = original >>> new.append(4) >>> new, original ([1, 2, 3, 4], [1, 2, 3, 4]) |
这按预期工作。
既然两者都是浅薄的拷贝,为什么
"浅复制"意味着字典的内容不是按值复制的,而是创建一个新的引用。
1 2 3 4 5 6 7 | >>> 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]}) |
相反,深度复制将按值复制所有内容。
1 2 3 4 5 6 7 | >>> 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]}) |
所以:
这不是深度复制或浅复制的问题,你所做的都不是深度复制。
在这里:
1 | >>> new = original |
您正在创建对原始引用的列表/dict的新引用。
在这里:
1 2 3 | >>> new = original.copy() >>> # or >>> new = list(original) # dict(original) |
您正在创建一个新的列表/dict,其中包含原始容器中对象引用的副本。
举个例子:
1 2 | original = dict(a=1, b=2, c=dict(d=4, e=5)) new = original.copy() |
现在,让我们在"浅层"(第一层)中更改一个值:
1 2 3 4 | 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 |
现在让我们更深入地改变一个值:
1 2 3 4 | 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 |
增加了肯尼特的答案。当您执行shallow copy parent.copy()时,将使用相同的键创建一个新字典,但不会复制这些值。如果您向parent_copy添加一个新值,则不会影响parent,因为parent_copy是一个新字典,而不是引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | parent = {1: [1,2,3]} parent_copy = parent.copy() parent_reference = parent print id(parent),id(parent_copy),id(parent_reference) #140690938288400 140690938290536 140690938288400 print id(parent[1]),id(parent_copy[1]),id(parent_reference[1]) #140690938137128 140690938137128 140690938137128 parent_copy[1].append(4) parent_copy[2] = ['new'] print parent, parent_copy, parent_reference #{1: [1, 2, 3, 4]} {1: [1, 2, 3, 4], 2: ['new']} {1: [1, 2, 3, 4]} |
父级[1]、父级副本[1]的哈希(ID)值相同,这意味着存储在ID 140690938288400的父级[1]和父级副本[1]的[1,2,3]。
但是父级和父级副本的哈希是不同的,这意味着它们是不同的字典,parent_copy是一个新的字典,它的值引用了parent的值。
"new"和"original"是不同的dict,这就是为什么您可以只更新其中一个。这些项目只是简单的复制,而不是听写本身。
内容是浅拷贝的。
因此,如果原始的
在第二部分中,您应该使用