2

Can anyone please explain what is happening here? I understand python ints are assigned by value (and not by reference).

>>> alist = [1,2,3]
>>> a = [[0]*3]*4
>>> a[0][0] = len(alist)
>>> alist.append(1)
>>> a[1][0] = len(alist)
>>> a[0][0]a
4
>>> 

4 Answers4

4

When you create a list using the * notation, you're repeating the same element. Not copies of the element, but the same exact object.

When the object you're repeating is immutable, such as an integer, you won't notice.

When the object is mutable, such as a list, you get the same list repeated. If you make a change to one list you're making it to all of them.

In your case you made a change to element [1] and it was reflected in element [0].

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
3

The problem is that your outer list contains multiple copies of the same inner list value. Here's how you can tell:

a = [[0]*3]*4
print(a[0] is a[1]) # prints True

If you want a two dimensional list of zeros, I suggest using a list comprehension for the outer part so that you get separate inner lists instances:

a = [[0]*3 for _ in range(4)]
print(a[0] is a[1]) # prints False

a[0][0]=1
print(a[1][0]) # prints 0
Blckknght
  • 100,903
  • 11
  • 120
  • 169
2

This might help (just dumping the values of list and a at each line):

#With some commentary
>>> alist = [1,2,3] #Created a list with 3 elements
>>> alist
[1, 2, 3]
>>> a = [[0]*3]*4 #Created a list with 3 copies of one element and then copied it 4 times
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0] = len(alist) #Set the 0th element of the 0th copy to 3
>>> a #Now you can see where that value was copied
[[3, 0, 0], [3, 0, 0], [3, 0, 0], [3, 0, 0]]
#The rest is just a permutation of that first 'bug'
>>> alist.append(1)
>>> alist
[1, 2, 3, 1]
>>> a[1][0] = len(alist)
>>> a
[[4, 0, 0], [4, 0, 0], [4, 0, 0], [4, 0, 0]]
>>> a[0][0]
4

An unintuitive thing about this code might be that [0]*3 seems do do what you expected while [[0]*3]*4 did not. For this I can only guess (not a Python guru yet) that a single length list of ints was handled in a way that seemed intuitive, while a list of lists fell back to a copy approach.

Jason Sperske
  • 29,816
  • 8
  • 73
  • 124
0

No problem. [[0]*3]*4 created a list with 4 copies of a list of 3 elements. a[0], a[1], a[2] and a[3] all point to the same list.

>>> a=[[0]*3]*4
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]='hello'
>>> a
[['hello', 0, 0], ['hello', 0, 0], ['hello', 0, 0], ['hello', 0, 0]]
>>> for mylist in a:
    ...     print id(a)
    ...
    42701168
    42701168
    42701168
    42701168
>>>
tdelaney
  • 73,364
  • 6
  • 83
  • 116