>>> 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:
In [1]: a = [[1]] In [2]: b = a + a In [3]: b Out[3]: [[1], [1]] In [4]: b[0][0] = 10 In [5]: b Out[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]*5 In [7]: for row in rows: ...: print id(row) ...: ...: 15975992 15975992 15975992 15975992 15975992
The following is equivalent to your example except it creates five distinct lists for the rows:
rows = [['']*5 for i in range(5)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With