1

I can't explain the behavior of this code:

n=[[0,0],[0,0]]
m=n.copy()
for i in range(len(m)):
     m[i]+=[0]

The output I get is (not what I expected):

>>> m
[[0, 0, 0], [0, 0, 0]]
>>> n
[[0, 0, 0], [0, 0, 0]]

If I type instead:

n=[[0,0],[0,0]]
m=n.copy()
for i in range(len(m)):
     m[i]=m[i]+[0]

I get the correct output (which is what I originally expected):

>>> m
[[0, 0, 0], [0, 0, 0]]
>>> n
[[0, 0], [0, 0]]

So, it looks like if I use the "+=" shortcut the two matrices "m" and "n" become aliases. Can somebody please explain why this is happening?.

paisanco
  • 4,098
  • 6
  • 27
  • 33

2 Answers2

2

n.copy() creates a shallow copy, so n[i] and m[i] are already pointing to the same object (although m and n are different).

For lists, x += y is not quite the same thing as x = x + y - the former mutates x directly (it's equivalent to x.extend(y)) while the latter assigns x to a new value.

These two facts combined explain the behaviour.

Alex Hall
  • 34,833
  • 5
  • 57
  • 89
1

The difference here is that some_list += some_iterable is effectively the same thing as some_list.extend(some_iterable).

some_list = some_list + [something_else] actually creates a new list out of some_list and [something_else] concatenated together and then assigns that new list back on the left hand side of the = operator.

When you think of it this way, and with the knowledge that after copying, m[idx] is n[idx] for all 0 <= idx < len(m)1, it's easier to see why the += version changes show up in both m and n.

1list.copy() makes a shallow copy -- which means that it only copies references.

mgilson
  • 300,191
  • 65
  • 633
  • 696