为什么 .append() 会影响列表列表中的所有元素?

问题描述 投票:0回答:4

我创建了一个列表列表,并希望将项目附加到各个列表,但是当我尝试附加到其中一个列表 (

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
成为 int 而不是列表,并将括号放在
.append()
内,给了我所需的输出:

a = []
b = 1

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

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

给予:

[[1, 2], [1, 3]]

但是为什么呢?结果应该不同是不直观的。我知道这与存在对同一列表的多个引用有关,但我不知道这是在哪里发生的。

python list append
4个回答
39
投票

这是因为列表包含对对象的引用。您的列表不包含

[[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])
)时都会创建新列表,因此它们是使用相同浮点值初始化的单独对象。


1
投票

为了制作列表的浅表副本,惯用语是

a.append(b[:])

当加倍时,将导致 a 拥有列表的两个新副本

b
,这不会给您报告的别名错误。


0
投票

问题是“a”有两次相同的列表。使用:

https://pypi.org/project/memory-graph/

您可以绘制数据图表并更好地了解共享哪些数据。当我更改您的代码以绘制数据图表时:

import memory_graph # see install instructions at link above
a = []
b = [1]

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

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

我得到:

很容易看出 'a' 有两次相同的列表,而仅打印 'a' 是看不到的。解决方案可能是复制“b”,例如:

import memory_graph
a = []
b = [1]

a.append(b.copy()) # <------ copy
a.append(b.copy()) # <------ copy

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

结果是:

并给出预期输出:[[1, 2], [1, 3]]

完全披露:我是memory_graph的开发者。

© www.soinside.com 2019 - 2024. All rights reserved.