理解dict.copy() – 浅或深?
在阅读dict.copy()
的文档时,它说它制作了字典的浅表副本。 (Beazley的Python参考资料)也是如此,他说:
m.copy()方法对映射对象中包含的项目进行浅度拷贝,并将它们放置在新的映射对象中。
考虑这个:
>>> 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}
所以我认为这会更新original
的值(并添加'c':3),因为我正在做一个浅拷贝。 就像你做一个清单一样:
>>> original = [1, 2, 3] >>> new = original >>> new.append(4) >>> new, original ([1, 2, 3, 4], [1, 2, 3, 4])
这按预期工作。
既然都是浅拷贝,为什么dict.copy()
不能像我期望的那样工作? 或者我对浅浅复制的理解是有缺陷的?
通过“浅拷贝”,它意味着字典的内容不被值复制,而是创build一个新的引用。
>>> 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]})
所以:
-
b = a
:引用赋值,使a
和b
指向同一个对象。 -
b = a.copy()
:浅拷贝,a
和b
将成为两个孤立的对象,但是它们的内容仍然共享相同的引用 -
b = copy.deepcopy(a)
:深拷贝,a
和b
的结构和内容完全隔离。
这不是一个深拷贝或浅拷贝的问题,你所做的一切都不是深拷贝。
这里:
>>> new = original
您正在创build对原始引用的列表/词典的新引用。
而这里:
>>> new = original.copy() >>> # or >>> new = list(original) # dict(original)
您正在创build一个新的列表/词典,其中填充了原始容器中包含的对象的引用的副本。
以这个例子:
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
“新”和“原”是不同的字典,这就是为什么你只能更新其中一个。这些项目是浅拷贝的,而不是字典本身。
增加kennytm的答案。 当你做一个浅的副本parent.copy()时,一个新的字典是用相同的键创build的。 值不会复制它们被引用。如果您将一个新值添加到parent_copy它不会影响父级,因为parent_copy是一个新的字典没有引用。
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]}
parent [1] , parent_copy [1]的哈希(id)值是相同的,这意味着存储在id为140690938288400的parent [1]和parent_copy [1]的 [1,2,3]。
但是parent和parent_copy的散列是不同的,这意味着它们是不同的字典,而parent_copy是一个新的字典,它具有值引用parent
内容被浅拷贝。
因此,如果原始dict
包含一个list
或其他dictionary
,修改它们在原来的或其浅的副本将修改他们( list
或dict
)在另一个。