有一个井字游戏程序,它首先创建一个游戏计划,其中每一行都是一个包含空填充符号的列表,这意味着方块是空的。
def createGamePlan(size, sign): gPlan = [] row = [sign]*size for i in range(size): gPlan.append(row) return gPlan
当用户选择行和列时,我希望更新该特定元素的符号。因此,如果我想将第二行的第一列更新为“X”,我会
def updateGamePlan(row, col, gamePlan, sign): gamePlan[1][0] = "X"
但是,这会改变每一行的第一列,我不知道为什么。我指定它是第二行(gamePlan 列表的第 1 个元素,以及该内部列表的第 0 个元素,即第一列)。有人能指出哪里出了问题吗,以及我如何才能在上面的例子中只改变第二行的第一列,而不是每一行
要理解的关键是list对象没有行和列。列表对象是有序的、异构的对象序列。当你这样做时:
list
def createGamePlan(size, sign): gPlan = [] row = [sign]*size for i in range(size): gPlan.append(row) # appends the SAME object return gPlan
因此,请考虑以下情况:
>>> a = ['foo'] >>> bar = [] >>> for _ in range(4): ... bar.append(a) ... >>> [id(x) for x in bar] [4534044744, 4534044744, 4534044744, 4534044744]
所有物件都一樣!
>>> bar[0].append('baz') >>> bar [['foo', 'baz'], ['foo', 'baz'], ['foo', 'baz'], ['foo', 'baz']]
您创建了一个包含相同对象多次的列表。解决方案是什么?附加一份副本。
def createGamePlan(size, sign): gPlan = [] row = [sign]*size for i in range(size): gPlan.append(row.copy()) # appends a NEW object return gPlan
但要小心,因为.copy只进行浅拷贝。考虑一下:
.copy
>>> row = [['foo'], ['bar']] >>> grid = [] >>> for _ in range(5): ... grid.append(row.copy()) ... >>> grid [[['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']]]
好的,太棒了!这些都是独立的物体!:
>>> [id(x) for x in grid] [4534044616, 4534135432, 4534135560, 4534135176, 4534135688]
那么…这应该可以正常工作,不是吗?
>>> grid[0][0].append('baz') >>> grid [[['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']]]
发生了什么事?其实,浅拷贝创建了新的列表,但没有创建新的子列表,也就是说,它没有复制元素中包含的任何元素:
>>> [id(x) for row in grid for x in row] [4534135048, 4534135112, 4534135048, 4534135112, 4534135048, 4534135112, 4534135048, 4534135112, 4534135048, 4534135112] >>>
为此,您需要一个deepcopy:
>>> import copy >>> row = [['foo'], ['bar']] >>> grid = [] >>> for _ in range(5): ... grid.append(copy.deepcopy(row)) ... >>> grid [[['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']]] >>> [id(x) for row in grid for x in row] [4534135432, 4534135368, 4534135176, 4534135880, 4534136328, 4534161928, 4534135112, 4534162120, 4534162248, 4534162184] >>> grid[0][0].append('baz') >>> grid [[['foo', 'baz'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']]] >>>