ars.me My personal website

(FAQ) Python list multiplication

Q: In Python, how come mutating one nested list in a list of lists mutates all of them in the following scenario?

>>> l = [[]] * 3
>>> l[0].append(42)
>>> l
[[42], [42], [42]]

The expected output is [[42], [], []].

A:

First of all, it’s important to understand that Python lists are actually lists of pointers. Each position of a list points to an object in memory. Therefore, multiple list positions can point to the same object.

Now to answer the question: it’s because multiplying a list duplicates the pointers to the elements as opposed to creating copies of them. In other words, the three nested lists in the example above are all really the same object that is being pointed to from three different places, so of course a change in one shows up in the others.

We can see this by using id():

>>> l = [[]] * 3
>>> id(l[0]), id(l[1]), id(l[2])
(2945232, 2945232, 2945232)

Notice that all three elements have the same identity.

Mutating one of the members of l here is kind of like doing the following:

>>> a = []
>>> l = [a, a, a]
>>> a.append(42)  # <--
>>> l
[[42], [42], [42]]

This is to be expected since l contains several references to the same object: a.

So, overall, the list [[]] * 3 looks like this:

        [ elem1, elem2, elem3 ]
            |      |      |
            |      |      |
            |      |      |
            +-->  [ ]  <--+

All three elements refer to the same list.

If you want to produce a list of n independent sublists, a list comprehension can be used instead of multiplication:

>>> l = [[] for _ in range(3)]
>>> l[0].append(42)
>>> l
[[42], [], []]

Now l looks like this:

        [ elem1, elem2, elem3 ]
            |      |      |
            |      |      |
            |      |      |
           [ ]    [ ]    [ ]

Each element is unique: mutating one will not affect the others.

As a result of all this, you should exercise caution when multiplying a list whose elements are mutable. For a list of immutable types, there will not be a problem of this kind, so something like [0] * 10 is perfectly valid and reasonable.