【问题标题】:Changing the nth element of a list in a list changes the nth element of all lists in the list [duplicate]更改列表中列表的第 n 个元素会更改列表中所有列表的第 n 个元素 [重复]
【发布时间】:2018-05-27 20:19:49
【问题描述】:

我有一个 tictactoe 程序,它首先创建一个游戏计划,其中每一行是一个包含一个空填充符号的列表,这意味着该正方形是空的。

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"

然而,这会改变 每一行 的第一列,我不知道为什么。我指定它的第 2 行(gamePlan 列表的第 1 个元素,以及该内部列表的第 0 个元素,即第 1 列)。有人可以指出哪里出了问题,我怎么能,在上面的例子中,只改变第二行的第一列,而不是每一行

【问题讨论】:

  • 我认为您需要复制该行:gPlan.append(row[:])
  • 我确定某处有此副本,但您在 gPlan 中附加了相同的 row
  • 我不认为这些是好的目标,问题在于[[]]*n,而这里不是* 运算符...

标签: python list


【解决方案1】:

要理解的关键是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 只会制作 副本。考虑:

>>> 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]
>>>

为此,您需要一个深拷贝

>>> 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']]]
>>>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2013-09-27
    • 2020-01-10
    • 2018-03-11
    相关资源
    最近更新 更多