18

Let's say I have the following code:

a_list = [[0]*10]*10

This generates the following list:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

Then I want to modify the first element in the first list:

a_list[0][0] = 23

I expected only the first element of the list to be modified, but actually the first element of each list was changed:

[[23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

I managed to find another way to represent my data to avoid this but why is this happening? Why isn't just the first list changed? When I do the second *10, does Python actually copy the first list's address instead of allocating a new memory block?

Virgiliu
  • 3,068
  • 6
  • 32
  • 55

3 Answers3

15

Your hunch about copying addresses is correct. Think about it like this:

sub_list = [0] * 10
a_list = [sub_list] * 10

This code is actually equivalent to the code you have posted above. What this means is that you are actually changing the same list sub_list whenever you change any element of a_list. You can even make sure of it by typing:

a_list = [[0] * 10] * 10
for n in a_list:
    print id(n)

And it will show up the same for every element. To remedy this, you should use:

a_list = [[0] * 10 for _ in range(10)]

In order to create a new sublist for every element of a_list.

146
  • 801
  • 6
  • 5
4

Lists contain references to objects. Multiplication on lists simply repeats the references (to the same objects!). While this is fine for immutable objects (like integers), what you are getting is multiple references to the same list.

Create separate lists with this pattern [[0]*10 for _ in xrange(10)].

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • But then why doesn't this happen in that first list, `[0]*10` ? This is also a list multiplication, but apparently here it is not just the reference to that first `0` that is repeated ...? – Rolf Bartstra Dec 06 '12 at 17:33
  • @RolfBartstra, it *is* the same reference to an **immutable** integer object that is repeated. You can't alter the contents of a integer object so you can't cause the same trouble as you can with a mutable list object. – Mark Tolonen Dec 06 '12 at 20:10
3

Why isn't just the first list changed?

The reason is simple, there really is only 1 list, not 10 - just as you already suspected:

In [1]: [[0]*10]*10
Out[1]:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

In [2]: map(id, _)
Out[2]:
[54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624]

If you want to create 10 lists, you can achieve this easily via an expression like

[[0]*10 for x in xrange(10)]
Jim Brissom
  • 31,821
  • 4
  • 39
  • 33