更改列表中列表的第n个元素会更改列表中所有列表的第n个元素 [英] Changing the nth element of a list in a list changes the nth element of all lists in the list

查看:99
本文介绍了更改列表中列表的第n个元素会更改列表中所有列表的第n个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a tictactoe program that first creates a gameplan where each row is a list containing an empty filler sign, which means the square is empty.

def createGamePlan(size, sign): 
    gPlan = []
    row = [sign]*size
    for i in range(size):
      gPlan.append(row)
    return gPlan

在用户选择行和列的情况下,我希望更新该特定元素的符号.因此,如果我想将第二行的第一列更新为"X",

With a users choice of row and column I wish to update the sign of that specific element. So if i want to update the 1st column of the 2nd row to an "X" I would have

def updateGamePlan(row, col, gamePlan, sign):
    gamePlan[1][0] = "X"

但是,这更改了每一行的第一列,我不知道为什么.我指定其第二行(gamePlan列表的第1个元素,以及内部列表的第0个元素,即第一列).在上面的示例中,有人可以指出出什么问题以及如何解决吗,只能使它更改第二行的第一列,而不是每一行

This however changes the 1st column of every single row and I cant figure out why. I specify that its the 2nd row (1-th element of the gamePlan list, and the 0-th element of that inner list i.e the 1st column). Can someone point out what goes wrong and how I can, in the example above, only make it change the 1st column of the 2nd row, and not every row

推荐答案

要理解的关键是list对象没有行和列.列表对象是对象的有序异类序列.当您这样做时:

The crucial thing to understand is that list objects do not have rows and columns. List objects are ordered, heterogeneous sequences of objects. When you do:

def createGamePlan(size, sign): 
    gPlan = []
    row = [sign]*size
    for i in range(size):
      gPlan.append(row) # appends the SAME object
    return gPlan

因此,请考虑以下事项:

So, consider the following:

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

您创建的列表多次包含同一对象.一个解法?附加副本.

You create a list that contains the same object many times. A solution? Append a copy.

def createGamePlan(size, sign): 
    gPlan = []
    row = [sign]*size
    for i in range(size):
      gPlan.append(row.copy()) # appends a NEW object
    return gPlan

但是请小心,因为.copy仅复制 shallow .考虑:

Be careful, though, because .copy only makes a shallow copy. Consider:

>>> row = [['foo'], ['bar']]
>>> grid = []
>>> for _ in range(5):
...     grid.append(row.copy())
...
>>> grid
[[['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']], [['foo'], ['bar']]]

好的,膨胀!这些都是独立的对象!:

OK, swell! these are all independant objects!:

>>> [id(x) for x in grid]
[4534044616, 4534135432, 4534135560, 4534135176, 4534135688]

所以...这应该工作正常,不是吗?

So... this should work fine, no?

>>> grid[0][0].append('baz')
>>> grid
[[['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']], [['foo', 'baz'], ['bar']]]

这是怎么回事?好吧,浅表副本创建了新列表,但没有创建新的子列表,即,它没有复制元素中包含的任何元素:

What's going on? Well, a shallow copy created new lists, but not new sublists, i.e., it didn't copy any elements contained in the elements:

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

这篇关于更改列表中列表的第n个元素会更改列表中所有列表的第n个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆