Python 3.3 Bug?将列表附加到列表:

时间:2013-08-13 14:49:54

标签: python arrays list append

我正在尝试制作可以2D阵列形式构建某种可编辑世界地图的代码:

class map(object):
    def __init__(self, width, height):
        self.__height = height
        self.__width = width

        self.__grid = []
        row = []
        for num in range(0, self.__width):
            row.append(".")
        for num in range(0, self.__height):
            self.__grid.append(row)
        print(self.__grid)

    def drawCell(self, X, Y, symbol):
        self.__grid[Y-1][X-1] = symbol
        print(self.__grid)

world = map(6, 4)
world.drawCell(3, 2, "0")

当我运行它时,它不是编辑单元格(3,2),而是在每行中执行第3个单元格。 奇怪的是,当我将 init ()更改为此...

    def __init__(self, width, height):
        self.__height = height
        self.__width = width

        self.__grid = [['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.']]

...以便 init 跳过网格的构造,它完美无缺!看起来它附加了变量'row'而不是它包含的值,因此它编辑了'row'的每个实例。

当然,上述解决方案不允许改变地图大小。所以我的问题是:这有什么非冗余的方法吗?

编辑:你不需要解释它为什么会发生,我已经解释过了。我想到当我做这个时它附加了值,而不是包含它的变量。

8 个答案:

答案 0 :(得分:1)

您正在创建一个列表,然后将该列表附加到self.__grid self.__height次。

改为附加副本:

for num in range(0, self.__height):
    self.__grid.append(row[:])

或者更好的是,使用生成器表达式生成整个网格:

self.__grid = [['.'] * self.__width for _ in self.__height]

答案 1 :(得分:0)

那是因为当你多次执行self.__grid.append(row)时,它每次都会对同一个列表对象附加一个引用,所以当你编辑对其中一个的引用时,你正在编辑所有的对象。引用。

这将做你想要的:

    self.__grid = []
    for num in range(0, self.__height):
        row = []
        for num in range(0, self.__width):
            row.append(".")
        self.__grid.append(row)

但是如果你使用列表推导它会更紧凑:

self.__grid = [['.' for a in range(self.__width)] for b in range(self.__height)]

这使得每一行都成为一个单独的列表对象的引用。

答案 2 :(得分:0)

您的问题是您没有构建(高度)不同的行,您构建了一个行列表并将其附加到self.__grid (高度)倍。这意味着更改一行将更改所有其他行,因为self.__grid的所有元素都引用了相同的列表对象。

在您的原始代码中,您可以通过更改此行来解决此问题:

self.__grid.append(row)

改为制作模板行的副本:

self.__grid.append(list(row))

答案 3 :(得分:0)

您的网格生成错误。

row = []
for num in range(0, self.__width):
    row.append(".")
for num in range(0, self.__height):
    self.__grid.append(row)

每次都追加相同的(在某种意义上它是相同的,同一列表的多个引用)行(注意row只定义了一次!)。将其更改为:

for num in range(0, self.__height):
    row = []
    for num2 in range(0, self.__width):
        row.append(".")
    self.__grid.append(row)

正如您所看到的,这不是Python中的错误。 :)

答案 4 :(得分:0)

这是因为当你这样做时:

self.__grid.append(row)

在第一个示例中,您将相同的row对象附加到每一行。如果你想避免这种情况,你可以这样做:

self.__grid.append(row[:])

创建副本。

答案 5 :(得分:0)

简单的NumPy实现:D

import numpy as np  

world = np.ones(shape = (6,4)).astype(str) #YourGrid
world[3,2] = "0" #DrawCell

print world

收率:

[['1.0' '1.0' '1.0' '1.0']
 ['1.0' '1.0' '1.0' '1.0']
 ['1.0' '1.0' '1.0' '1.0']
 ['1.0' '1.0' '0' '1.0']
 ['1.0' '1.0' '1.0' '1.0']
 ['1.0' '1.0' '1.0' '1.0']]

答案 6 :(得分:0)

很好的答案,但我也提到它可以缩短为

self.__grid = [['.'] * self.__height for i in range(self.__width)]

答案 7 :(得分:0)

本质上,python中的列表是对象,当您将列表/对象分配给变量时,您只需将指针传递给它。当您将列表附加到另一个列表时也是如此。因此,在这种情况下,您最终会多次将指针附加到同一个对象(这就是为什么当您编辑一个时编辑所有对象的原因)。

您必须重新创建多个实例(查找列表推导,初始化多维列表的一种简洁方法),或者在追加它们时复制列表。