关于这个问题:
在使用二维数组时,我发现以某种方式初始化它会产生意想不到的结果。我想了解以这两种方式初始化 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]]
Run Code Online (Sandbox Code Playgroud)
对比
>>> 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]]
Run Code Online (Sandbox Code Playgroud)
出乎意料的结果是任何使用 indeces [0-6][x] 访问的元素都将指向 [7][x] 中的最后一行。数组在解释器中看起来相同,因此我很困惑。第一种方法有什么问题?
如果相关,这些数组包含对代表棋盘方格的 GTK EventBoxes 的引用。将初始化方法更改为列表理解方法后,方块会正确响应预期的悬停和点击事件。
在您的第一个版本中,您将创建一个包含数字 1 的列表,并将其乘以 8 次,创建一个包含 8 个 1 的列表,然后使用该列表 8 次来创建a。
因此,当您在第一个版本中更改任何内容时,您会在其他地方看到该更改。您的问题是您正在重复使用同一个实例,这在第二个版本中不会发生。
当您使用a = [[1]*8]*8* 运算符创建2D 数组时,会创建对同一对象的 8 个引用。因此,[1]*8意味着创建一个大小为 8 的数组,其中所有 8 个元素都是相同的对象(相同的引用)。由于所有元素都是相同的引用,更新该引用指向的值将改变数组中每个元素的值。
使用列表推导式A = [[1 for i in range(8)] for j in range(8)]可确保 2D 数组中的每个元素都被唯一引用。这避免了您看到的所有元素同时更新的错误行为。