了解dict.copy() - 浅或深?

时间:2010-10-20 06:51:26

标签: python

在阅读dict.copy()的文档时,它说它是字典的浅层副本。我所遵循的书(Beazley的Python参考资料)也是如此,它说:

  

m.copy()方法很浅   a。中包含的项目的副本   映射对象并将它们放在一个   新的映射对象。

考虑一下:

>>> 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()不能像我期望的那样工作?或者我对浅层复制和深层复制的理解存在缺陷?

7 个答案:

答案 0 :(得分:894)

通过“浅层复制”,它意味着字典的内容不会被值复制,而只是创建新的引用。

>>> 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]})

所以:

  1. b = a:引用分配,将ab指向同一个对象。

    Illustration of 'a = b': 'a' and 'b' both point to '{1: L}', 'L' points to '[1, 2, 3]'.

  2. b = a.copy():浅层复制,ab将成为两个独立的对象,但其内容仍然共享相同的引用

    Illustration of 'b = a.copy()': 'a' points to '{1: L}', 'b' points to '{1: M}', 'L' and 'M' both point to '[1, 2, 3]'.

  3. b = copy.deepcopy(a):深层复制,ab的结构和内容完全隔离。

    Illustration of 'b = copy.deepcopy(a)': 'a' points to '{1: L}', 'L' points to '[1, 2, 3]'; 'b' points to '{1: M}', 'M' points to a different instance of '[1, 2, 3]'.

答案 1 :(得分:37)

这不是深拷贝或浅拷贝的问题,你所做的都不是深拷贝。

下面:

>>> new = original 

您正在创建对原始引用的列表/字典的新引用。

在这里:

>>> new = original.copy()
>>> # or
>>> new = list(original) # dict(original)

您正在创建一个新的列表/字典,其中包含原始容器中包含的对象引用的副本。

答案 2 :(得分:25)

举个例子:

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

答案 3 :(得分:7)

添加到kennytm的答案。当你执行浅拷贝 parent.copy() 时,会创建一个使用相同键的新词典,但不会复制它们,而是引用它们。如果添加新值 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] 的哈希(id)值, parent_copy [1] 是相同的意味着[1,2>]的 父[1] parent_copy [1] 存储在id 140690938288400

但是 parent_copy 的哈希是不同的 它们是不同的词典, parent_copy 是一个新词典,其值引用

的值

答案 4 :(得分:5)

“new”和“original”是不同的dicts,这就是为什么你只能更新其中一个.. items 是浅层复制的,而不是dict本身。

答案 5 :(得分:2)

内容被浅层复制。

因此,如果原始dict包含list或其他dictionary,则在原始版本或其浅版本中修改它们将修改它们(list或{ {1}})在另一个。

答案 6 :(得分:1)

在第二部分中,您应该使用new = original.copy()

.copy=是不同的事情。