为啥 foo.append(bar) 会影响列表列表中的所有元素?

Posted

技术标签:

【中文标题】为啥 foo.append(bar) 会影响列表列表中的所有元素?【英文标题】:Why does foo.append(bar) affect all elements in a list of lists?为什么 foo.append(bar) 会影响列表列表中的所有元素? 【发布时间】:2011-09-15 15:51:06 【问题描述】:

我创建了一个列表列表并希望将项目附加到各个列表中,但是当我尝试附加到其中一个列表 (a[0].append(2)) 时,该项目会添加到所有列表中。

a = []
b = [1]

a.append(b)
a.append(b)

a[0].append(2)
a[1].append(3)
print(a)

给:[[1, 2, 3], [1, 2, 3]]

而我期望:[[1, 2], [1, 3]]

改变我构造初始列表的方式,使 b 成为浮点数而不是列表并将括号放在 .append() 内,给了我想要的输出:

a = []
b = 1

a.append([b])
a.append([b])

a[0].append(2)
a[1].append(3)
print(a)

给:[[1, 2], [1, 3]]

但是为什么呢?结果应该不同是不直观的。我知道这与 multiple references to the same list 的存在有关,但我不知道发生在哪里。

【问题讨论】:

【参考方案1】:

这是因为列表包含对对象的引用。您的列表不包含[[1 2 3] [1 2 3]],而是[<reference to b> <reference to b>]

当您更改对象时(通过向b 附加一些内容),您更改的是对象本身,而不是包含该对象的列表。

要获得您想要的效果,您的列表a 必须包含b 的副本,而不是对b 的引用。要复制列表,您可以使用范围[:]。例如:

>>> a=[]
>>> b=[1]
>>> a.append(b[:])
>>> a.append(b[:])
>>> a[0].append(2)
>>> a[1].append(3)
>>> print a
[[1, 2], [1, 3]]

【讨论】:

谢谢,现在很有意义。【参考方案2】:

关键是这部分:

a.append(b)
a.append(b)

您将同一个列表追加两次,因此a[0]a[1] 都是对同一个列表的引用。

在第二个示例中,每次调用 append 时都会创建新列表,例如 a.append([b]),因此它们是使用相同浮点值初始化的单独对象。

【讨论】:

谢谢,这个回答也增加了我的理解。【参考方案3】:

为了做一个列表的浅拷贝,成语是

a.append(b[:])

当它加倍时,会导致 a 有两个新的列表 b 副本,这不会给您报告的别名错误。

【讨论】:

以上是关于为啥 foo.append(bar) 会影响列表列表中的所有元素?的主要内容,如果未能解决你的问题,请参考以下文章

为啥插入方法会影响两个列表? [复制]

为啥列表推导会影响外部变量的值? [复制]

SQL优化,列列表上的条件会影响优化吗?

为啥 'foo bar' 和 'foo > bar' 在 CSS 中具有相同的特性?

Django 会话变量重置

Postgres 表中列的顺序会影响性能吗?