Element (array) “multiplication” vs. list comprehe

2020-07-19 03:27发布

In relation to the question:

How to initialize a two-dimensional array in Python?

While working with a two dimentional array, I found that initializing it in a certain way would produce unexpected results. I would like to understand the difference between initializing an 8x8 grid in these two ways:

>>> a =  [[1]*8]*8
>>> a
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]]

vs.

>>> A =  [[1 for i in range(8)] for j in range(8)]
>>> A
[[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], \
 [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]]

The unexpected results were that any element accessed with the indeces [0-6][x] would point to the last row in [7][x]. The arrays look identical in the interpreter, hence my confusion. What is wrong with the first approach?

If relevant, these arrays hold references to GTK EventBoxes that represent the squares of a chess board. After changing the initialization approach to the list-comprehension method, the squares respond properly to the intended hover and click events.

标签: python arrays
3条回答
▲ chillily
2楼-- · 2020-07-19 04:03

In your first version, you're creating a list containing the number 1 and by multiplying it 8 times create a list containing 8 1s, and using that list 8 times to create a.

So when you change anything in the first version, you'll see that change everywhere else. Your problem being that you're reusing the same instance, something that doesn't happen in the second version.

查看更多
萌系小妹纸
3楼-- · 2020-07-19 04:17

When you create the 2D array using a = [[1]*8]*8 then the * operator creates 8 references to the same object. Therefore, [1]*8 means create an array of size 8 where all 8 elements are the same object (same reference). Since all elements are the same references updating the value to which that reference points will change the value of every element in the array.

Using the list comprehension A = [[1 for i in range(8)] for j in range(8)] ensures that each element in your 2D array is uniquely referenced. This avoids the erroneous behavior you were seeing where all of the elements were updating simultaneously.

查看更多
爷的心禁止访问
4楼-- · 2020-07-19 04:20

maybe refactoring the first way make it eeasier to understand:

one_item = [1]
row = one_item*8
matrix = row*8

as you can see, the array of arrays has eight references to row, which means

(a[0] is a[1]) and (a[1] is a[2]) ...

try this for example:

a = [[1]*8]*8
a[0][0] = 2

b = [[1 for i in range(8)] for j in range(8)]
b[0][0] = 3

print a
print b

print (a[0] is a[1]) and (a[1] is a[2]) and (a[2] is a[3]) # true

print (b[0] is b[1]) and (b[1] is b[2]) and (b[2] is b[3]) # false
查看更多
登录 后发表回答