>>> rows = [['']*5]*5
>>> rows
[['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', '']]
>>> rows[0][0] = 'x'
Naturally, I expect rows to become:
[['x', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', '']]
Instead, I get:
[['x', '', '', '', ''], ['x', '', '', '', ''], ['x', '', '', '', ''], ['x', '', '', '', ''], ['x', '', '', '', '']]
It seems that elements of rows list are pointers to the same old [”]*5 list. Why does it work this way and is this a Python feature?
The behaviour is not specific to the repetition operator (
*). For example, if you concatenate two lists using+, the behaviour is the same: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
rowshave the same identity (i.e. memory address in CPython):The following is equivalent to your example except it creates five distinct lists for the rows: