由列表乘法创建的嵌套引用列表的Deepcopy不起作用

时间:2011-02-01 17:25:13

标签: python list nested multiplication deep-copy

尽管我喜欢Python,但引用和深度复制的东西有时会让我感到厌烦。

为什么深度复制在这里不起作用:

>>> import copy
>>> a = 2*[2*[0]]
>>> a
[[0, 0], [0, 0]]
>>> b = copy.deepcopy(a)
>>> b[0][0] = 1
>>> b
[[1, 0], [1, 0]]     #should be: [[1, 0], [0, 1]]
>>> 

我正在使用一个numpy数组作为一个workarround,无论如何我以后需要。但我真的希望如果我使用deepcopy,我就不必再追逐任何非预期的引用了。是否有更多陷阱不起作用?

2 个答案:

答案 0 :(得分:13)

它不起作用,因为您正在创建一个包含对同一数组的两个引用的数组。

另一种方法是:

[[0]*2 for i in range(2)]

或者更明确:

[[0 for j in range(2)] for i in range(2)]

这是有效的,因为它在每次迭代时都会创建一个新数组。

  

是否有更多陷阱不起作用?

每当你有一个包含引用的数组时,你应该小心。例如,[Foo()] * 2[Foo() for i in range(2)]不同。在第一种情况下,只构造了一个对象,并且该数组包含两个对象。在第二种情况下,构造了两个独立的对象。

答案 1 :(得分:7)

它完全按照您的预期运作。

a = 2 * [2 * [0]]

当您将[[0,0]]2 *相乘时,新列表的两个元素都将指向SAME [0,0]列表。 a[0]a[1]是相同的列表,因为复制了引用,而不是数据(这是不可能的)。更改其中一个元素的第一个元素会改变另一个元素的第一个元素。

copy.deepcopy正确复制列表,保留唯一对象。