我创建了一个列表列表,并希望将项目附加到各个列表,但是当我尝试附加到其中一个列表 (
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]]
但是为什么呢?结果应该不同是不直观的。我知道这与存在对同一列表的多个引用有关,但我不知道这是在哪里发生的。
这是因为列表包含对对象的引用。您的列表不包含
[[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]]
关键是这部分:
a.append(b)
a.append(b)
您将同一列表追加两次,因此
a[0]
和 a[1]
都是对同一列表的引用。
在第二个示例中,每次调用append(如
a.append([b])
)时都会创建新列表,因此它们是使用相同浮点值初始化的单独对象。
为了制作列表的浅表副本,惯用语是
a.append(b[:])
当加倍时,将导致 a 拥有列表的两个新副本
b
,这不会给您报告的别名错误。
问题是“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的开发者。