1

I'm trying to create a list containing multiple lists filled with the same values this way:

l1 = [[False] * n] * m

There are no any errors and at first glance it looks like valid lists of lists (print(l1) for n=m=3 : [[False,False,False],[False,False,False],[False,False,False]])

But when I tried l1[0][0] = True I got a strange behaviour - list has turned into [[True,False,False],[True,False,False],[True,False,False]].

So, why did such list initialization results to it? And what should I do to create a list properly?

Uroboros
  • 189
  • 2
  • 12

2 Answers2

5
l1 = [[False] * n] * m
# I assume this is what you did, since 
# [False * 3] == [0], and not [False, False, False]

takes the same list instance [False * n] m times. Changing one reference to said instance will affect all references. Use a comprehension instead to create independent lists:

l1 = [[False] * n for _ in range(m)]

One should note that this works because bool is an immutable type. If you had a mutable type, let's say X, you would have to use a comprehension for the inner list, too:

l1 = [[X() for _ in range(n)] for _ in range(m)]
user2390182
  • 72,016
  • 6
  • 67
  • 89
3

That is because there is actually only one nested list. What you are seeing in the outer list is actually three references to what is in fact the same list.

You can easily observe this if you use a custom object:

class MyClass:
    def __init__(self):
        pass

a = MyClass()
l = [[a] * 2]

Printing l produces the following output:

[<__main__.MyClass object at 0x000000000462A2E8>, <__main__.MyClass object at 0x000000000462A2E8>]

Notice how the memory addresses are the same, because it is the same object. It is just referenced twice in the list. Modifying it via one index is the same as modifying it via another or directly. Changing it updates it everywhere.

Similarly, when you modify the nested list by doing l1[0][0] = True, all references to the list object are updated, leading to what you are seeing.

stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53