3

When I create and fill a list of lists some odd behaviour pops up:

list1 = [[0,0,0],[0,0,0],[0,0,0]]
list2 = [[0]*3]*3

print('lists still look equal here:')
print(list1)
print(list2)

list1[1].pop(1)
list2[1].pop(1)

print('but not anymore:')
print(list1)
print(list2)

gives me this output:

lists look completely equal here:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
but not anymore:
[[0, 0, 0], [0, 0], [0, 0, 0]]
[[0, 0], [0, 0], [0, 0]]

So the second list 'pops' from every little list instead of just the one I'm trying to. I wonder what causes this behaviour and if there is a more elegant way to fill indexable lists if I need a large amount of long lists instead of just these tiny ones?

2 Answers2

1

When using the operator * it means the items are pointing to the same memory location.

Therefore when poping from the first list only the first item is removed.

And when poping from the second list, as each of the elements in the list pointing to the same memory location, all elements get affected.

Take a look at this:

list1 = [[0,0,0],[0,0,0],[0,0,0]]
list2 = [[0]*3]*3

for elem in list1:
    print (id(elem))

print ('--------')
for elem in list2:
    print (id(elem))

Output:

32969912
32937024
32970192
--------
32970752
32970752
32970752

As you can see, each element in the second list has the same id.

omri_saadon
  • 10,193
  • 7
  • 33
  • 58
1

This is quite a common mistake. In the second definition:

list2 = [[0] * 3]*3

the three sub-lists share the same reference in memory, so if you pop from one, you pop from "all" of them, because all three of them point to the same object.

To avoid this, use:

list2 = [[0] * 3 for _ in range(3)]

which will generate different three lists.

Menglong Li
  • 2,177
  • 14
  • 19