为什么 .append() 会影响列表列表中的所有元素?
- 2025-02-14 09:50:00
- admin 原创
- 46
问题描述:
我创建了一个列表列表,并想将项目附加到各个列表中,但是当我尝试附加到其中一个列表(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:
这是因为列表包含对对象的引用。您的列表不包含[[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 like 时都会创建新列表a.append([b])
,因此它们是使用相同浮点值初始化的单独对象。
解决方案 3:
为了制作列表的浅拷贝,习惯用法是
a.append(b[:])
当其加倍时将导致拥有列表的两个新副本b
,这样就不会产生您报告的别名错误。
解决方案 4:
问题是 'a' 有两次相同的列表。使用:
https://pypi.org/project/memory-graph/
你可以绘制数据图表,更好地了解哪些数据是共享的。当我修改你的代码来绘制数据图表时:
import memory_graph as mg # 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)
mg.show(locals()) # draw graph
我得到:
很容易看出“a”有两次相同的列表,而仅打印“a”是看不到的。解决方案可能是复制“b”,如下所示:
import memory_graph as mg
a = []
b = [1]
a.append(b.copy()) # <------ copy
a.append(b.copy()) # <------ copy
a[0].append(2)
a[1].append(3)
print(a)
mg.show(locals())
其结果是:
并给出预期输出:[[1, 2], [1, 3]]
全面披露:我是memory_graph的开发者。