关于python:为什么foo.append(bar)会影响列表列表中的所有元素?

Why does foo.append(bar) affect all elements in a list of lists?

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
5
6
7
8
9
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()中,这样我得到了所需的输出:

1
2
3
4
5
6
7
8
9
a = []
b = 1

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

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

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

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


这是因为列表包含对对象的引用。您的列表不包含[[1 2 3] [1 2 3]],它是[ ]

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

为了达到你想要的效果,你的清单a必须包含b的副本,而不是引用b。要复制列表,可以使用范围[:]。例如,:

1
2
3
4
5
6
7
8
>>> a=[]
>>> b=[1]
>>> a.append(b[:])
>>> a.append(b[:])
>>> a[0].append(2)
>>> a[1].append(3)
>>> print a
[[1, 2], [1, 3]]


关键是这一部分:

1
2
a.append(b)
a.append(b)

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

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


为了简单地复制一个列表,习语是

1
a.append(b[:])

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