关于这个问题:
How to initialize a two-dimensional array in Python?
在使用二维数组时,我发现以某种方式初始化它会产生意想不到的结果。我想了解以这两种方式初始化8x8网格之间的区别:
>>> 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]]
意外的结果是,使用indeces [0-6] [x]访问的任何元素都将指向[7] [x]中的最后一行。数组在解释器中看起来相同,因此我的困惑。第一种方法有什么问题?
如果相关,这些数组会保存对代表棋盘方格的GTK EventBox的引用。将初始化方法更改为list-comprehension方法后,方块会正确响应预期的悬停和单击事件。
答案 0 :(得分:3)
使用a = [[1]*8]*8
创建2D数组时,*运算符会创建对同一对象的8个引用。因此,[1]*8
表示创建一个大小为8的数组,其中所有8个元素都是同一个对象(相同的引用)。由于所有元素都是相同的引用,因此更新引用点将更改数组中每个元素的值的值。
使用list comprehension A = [[1 for i in range(8)] for j in range(8)]
可确保2D数组中的每个元素都被唯一引用。这可以避免您在所有元素同时更新时看到的错误行为。
答案 1 :(得分:1)
在您的第一个版本中,您创建一个包含数字1的列表,并将其乘以8次创建一个包含8个1的列表,并使用 列表8次创建{{1} }。
因此,当您更改第一个版本中的任何内容时,您会在其他任何位置看到此更改。你的问题是你正在重复使用同一个实例,这在第二个版本中不会发生。
答案 2 :(得分:0)
也许重构第一种方式让它更容易理解:
one_item = [1]
row = one_item*8
matrix = row*8
如您所见,数组数组有八个对行的引用,这意味着
(a[0] is a[1]) and (a[1] is a[2]) ...
试试这个例子:
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