我正在尝试制作可以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'的每个实例。
当然,上述解决方案不允许改变地图大小。所以我的问题是:这有什么非冗余的方法吗?
编辑:你不需要解释它为什么会发生,我已经解释过了。我想到当我做这个时它附加了值,而不是包含它的变量。
答案 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中的列表是对象,当您将列表/对象分配给变量时,您只需将指针传递给它。当您将列表附加到另一个列表时也是如此。因此,在这种情况下,您最终会多次将指针附加到同一个对象(这就是为什么当您编辑一个时编辑所有对象的原因)。
您必须重新创建多个实例(查找列表推导,初始化多维列表的一种简洁方法),或者在追加它们时复制列表。