Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

>>> 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?

like image 657
xyzman Avatar asked Jan 11 '12 16:01

xyzman


1 Answers

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)] 
like image 77
NPE Avatar answered Sep 28 '22 03:09

NPE