[Tutor] Weird list indexing

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Wed Jul 9 17:26:02 2003


On Wed, 9 Jul 2003, Zak Arntson wrote:

> Now, why does this happen? I'm using Python 2.2.3, by the way.
>
> ###
>
> >>> a = [[None] * 3] * 3
> >>> a
> [[None, None, None], [None, None, None], [None, None, None]]
> >>> a[1][2] = 'a'
> >>> a
> [[None, None, 'a'], [None, None, 'a'], [None, None, 'a']]
>
> ###
>
> My guess is that the three lists are all the same object, just pointed to
> three different times? So it seems my shortcut to create a two-dimensional
> array doesn't work. Is there better shortcut?


Yes, exactly.


A common idiom for making 2d arrays in Python is a list comprehension
approach:

###
>>> a = [ [None] * 4
...       for i in range(7) ]
>>> a
[[None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None]]
>>> a[1][1] = "Foo!"
>>> a
[[None, None, None, None],
 [None, 'Foo!', None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None],
 [None, None, None, None]]
###


This works because the subexpression in our list comprehension,

    [ [None] * 4    for i in range(7) ]
      ^^^^^^^^^^

is evaluated more than once.  We get a new sublist for each row in our
matrix, so we're able to avoid the shared-structure problem that you saw.



Now that we know this, we can make a small utility function to construct
2d arrays for us:

###
>>> def makeArray(rows, cols):
...     return [ [None] * cols for i in range(rows) ]
...
>>> makeArray(2, 3)
[[None, None, None],
 [None, None, None]]
###


Good luck to you!