3

I tested the following python code on Spyder IDE. Thinking it would output 2d array q as increasing number as 0..31 from q[0][0] to q[3][7]. But it actually returns q as:

[[24, 25, 26, 27, 28, 29, 30, 31], [24, 25, 26, 27, 28, 29, 30, 31], [24, 25, 26, 27, 28, 29, 30, 31], [24, 25, 26, 27, 28, 29, 30, 31]]. 

The code:

q=[[0]*8]*4 
for i in range(4): 
    for j in range(8): 
        q[i][j] = 8*i+j 
print q

Any idea of what's happening here? I debugged step by step. It shows the updates of every row will sync with all other rows, quite different from my experience of other programing languages.

3 Answers 3

4
q=[somelist]*4 

creates a list with four identical items, the list somelist. So, for example, q[0] and q[1] reference the same object.

Thus, in the nested for loop q[i] is referencing the same list regardless of the value of i.

To fix:

q = [[0]*8 for _ in range(4)]

The list comprehension evaluates [0]*8 4 distinct times, resulting in 4 distinct lists.


Here is a quick demonstration of this pitfall:

In [14]: q=[[0]*8]*4

You might think you are updating only the first element in the second row:

In [15]: q[1][0] = 100

But you really end up altering the first element in every row:

In [16]: q
Out[16]: 
[[100, 0, 0, 0, 0, 0, 0, 0],
 [100, 0, 0, 0, 0, 0, 0, 0],
 [100, 0, 0, 0, 0, 0, 0, 0],
 [100, 0, 0, 0, 0, 0, 0, 0]]
Sign up to request clarification or add additional context in comments.

4 Comments

How about j in this case? Is it supposed to be all q[i][0] and q[i][1] reference the same object as well?
@user1640608 when you are using primitives (integer, etc), the reference isn't repeated.
Lists are mutable, integers are not. So if q[0] and q[1] point to the same list, then q[0][j] = 100 will modify q[1][j] as well. Although [0]*8 does create a list with 8 references to the same integer, it does not cause a problem because we aren't mutating the integers (an impossibility); we only alter the list's reference to point at other values.
@user1640608: see this old answer of mine: Python list doesn't reflect variable change, new to python; perhaps it'll help you understand what is going on.
1

As explained the problem is caused due to * operation on lists, which create more references to the same object. What you should do is to use append:

q=[]
for i in range(4): 
    q.append([])
    for j in range(8): 
        q[i].append(8*i+j)
print q 

[[0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23], [24, 25, 26, 27, 28, 29, 30, 31]]

Comments

0

When you do something like l = [x]*8 you are actually creating 8 references to the same list, not 8 copies.

To actually get 8 copies, you have to use l = [[x] for i in xrange(8)]

>>> x=[1,2,3]
>>> l=[x]*8
>>> l
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> l[0][0]=10
>>> l
[[10, 2, 3], [10, 2, 3], [10, 2, 3], [10, 2, 3], [10, 2, 3], [10, 2, 3], [10, 2, 3], [10, 2, 3]]
>>> l = [ [x] for i in xrange(8)]
>>> l
[[[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]]]
>>> l[0][0] = 1
>>> l
[[1], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]], [[10, 2, 3]]]

1 Comment

Not correct because what you are saying is [0]*8 will create repeated references, which it will not, only something like [[0]]*8 will do such a thing because the outer [] will contain a reference and not a primitive.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.