8

As much as I love Python, the reference and deepcopy stuff sometimes freaks me out.

Why does deepcopy not work here:

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

I am using a numpy array as a workarround which I need later on anyway. But I really had hoped that if I used deepcopy I would not have to chase any unintended references any more. Are there any more traps where it does not work?

Gonzo
  • 2,023
  • 3
  • 21
  • 30

2 Answers2

17

It doesn't work because you are creating an array with two references to the same array.

An alternative approach is:

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

Or the more explicit:

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

This works because it creates a new array on each iteration.

Are there any more traps where it does not work?

Any time you have an array containing references you should be careful. For example [Foo()] * 2 is not the same as [Foo() for i in range(2)]. In the first case only one object is constructed and the array contains two references to it. In the second case, two separate objects are constructed.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • Thanks for the quick answers. I appreciate your elegant solution. Still, it seems to me the deepcopy manual is misleading ("A deep copy constructs a new compound object and then, recursively, inserts *copies* into it of the objects found in the original."). It would be nice to have a function doing what I would expect deepcopy to do: get rid of all double references. – Gonzo Feb 01 '11 at 21:28
7

It works exactly as you have expected.

a = 2*[2*[0]]

When you multiply [[0,0]] with 2 *, both elements of the new list will point to the SAME [0,0] list. a[0] and a[1] are the same list, because the reference is copied, not the data (which would be impossible). Changing the first element of one of them changes the first element of the other.

copy.deepcopy copies the list correctly, preserving unique objects.

Rosh Oxymoron
  • 20,355
  • 6
  • 41
  • 43