Python 3.3错误?将列表附加到列表中:
我试图编写代码,以2D数组的形式构建某种可编辑的世界地图: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.
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循环,但我认为这并不重要。