Python 3.3错误?将列表附加到列表中:

Python 3.3错误?将列表附加到列表中:,python,arrays,list,append,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.

我试图编写代码,以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),而是在每行中编辑第三个单元格。 奇怪的是,当我将init更改为这个时

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

        self.__grid = [['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.']]
…因此,init跳过了网格的构建,它可以完美地工作!它看起来像是在附加变量“row”而不是它包含的值,因此它会编辑“row”的每个实例

当然,上述解决方案不允许改变贴图大小。所以我的问题是:有没有一种非冗余的方法来解决这个问题


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

这是因为当你做
self.\uu 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)]

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

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

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

self.__grid.append(row)
要制作模板行的副本,请执行以下操作:

self.__grid.append(list(row))

您的网格生成错误

row = []
for num in range(0, self.__width):
    row.append(".")
for num in range(0, self.__height):
    self.__grid.append(row)
您每次都在追加相同的行(从某种意义上说,它实际上是相同的,同一列表的多个引用)(请注意,
仅定义了一次!)。将此更改为:

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

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

您正在创建一个列表,然后将该列表附加到
self.\uuu网格中

改为附加副本:

for num in range(0, self.__height):
    self.__grid.append(row[:])
或者更好的是,使用生成器表达式生成整个栅格:

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

这是因为当您这样做时:

self.__grid.append(row)
在第一个示例中,您将向每一行追加相同的
对象。如果要避免这种情况,可以执行以下操作:

self.__grid.append(row[:])

创建副本。

简单的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']]

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

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

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


你要么重新创建多个实例(查找列表理解,一种简单的初始化多维列表的方法),要么在附加它们时复制列表。

你考虑过使用NumPy?Rob吗,这让我大吃一惊。我的老师似乎教了我对变量的简单理解。谢谢!我认为freakish的解决方案更简洁,但这教会了我一个关于这个问题的有用python技巧。谢谢!我有一种感觉,它应该看起来像一个嵌套的for循环,但我认为这并不重要。