Why does using multiplication operator on list create list of pointers? [duplicate] Why does using multiplication operator on list create list of pointers? [duplicate] python python

Why does using multiplication operator on list create list of pointers? [duplicate]


The behaviour is not specific to the repetition operator (*). For example, if you concatenate two lists using +, the behaviour is the same:

In [1]: a = [[1]]In [2]: b = a + aIn [3]: bOut[3]: [[1], [1]]In [4]: b[0][0] = 10In [5]: bOut[5]: [[10], [10]]

This has to do with the fact that lists are objects, and objects are stored by reference. When you use * et al, it is the reference that gets repeated, hence the behaviour that you're seeing.

The following demonstrates that all elements of rows have the same identity (i.e. memory address in CPython):

In [6]: rows = [['']*5]*5In [7]: for row in rows:   ...:     print id(row)   ...:        ...:     1597599215975992159759921597599215975992

The following is equivalent to your example except it creates five distinct lists for the rows:

rows = [['']*5 for i in range(5)]


The fact that names, function parameters, and containers have reference semantics is a very basic design decision in Python. It affects the way Python works in many aspects, and you picked just one of these aspects. In many cases, reference semantics are more convenient, while in other cases copies would be more convenient. In Python, you can always explicitly create a copy if needed, or, in this case, use a list comprehension instead:

rows = [[''] * 5 for i in range(5)]

You could design a programming language with different semantics, and there are many languages that do have different semantics, as well as languages with similar semantics. Why this decision was made is a bit hard to answer -- a language just has to have some semantics, and you can always ask why. You could as well ask why Python is dynamically typed, and in the end the answer is that this is just was Guido decided way back in 1989.


You are correct that Python is using pointers "under the hood", and yes, this is a feature. I don't know for sure why they did it this way- I assume it was for speed and to reduce memory usage.

This issue is, by the way, why it is critical to understand the distinction between shallow copies and deep copies.