使用乘法(*)产生意外行为的子列表
这个问题已经在这里有了答案 :
列表更改列表意外地反映在子列表中 (16个答案)
嵌套列表索引[重复项] (2个答案)
7年前关闭。
我确定这已经在某处得到了回答,但是我不确定如何描述它。
假设我要创建一个包含3个空列表的列表,如下所示:
lst = [[], [], []]
我以为自己很聪明:
lst = [[]] * 3
但是我发现,在调试了一些奇怪的行为之后,这导致对一个子列表的追加更新,例如lst[0].append(3)
更新了整个列表,[[3], [3],
[3]]
而不是[[3], [], []]
。
但是,如果我用
lst = [[] for i in range(3)]
然后做得到lst[1].append(5)
预期[[], [5], []]
我的问题是 为什么会这样 ?有趣的是,如果我这样做
lst = [[]]*3
lst[0] = [5]
lst[0].append(3)
然后单元格0的“链接”被破坏了,我得到了[[5,3],[],[]]
,但lst[1].append(0)
仍然会导致[[5,3],[0],[0]
。
我最好的猜测是,在表格中使用乘法[[]]*x
会导致Python存储对单个单元格的引用…?
-
我最好的猜测是,在表格中使用乘法
[[]] * x
会导致Python存储对单个单元格的引用…?是。你可以自己测试
>>> lst = [[]] * 3 >>> print [id(x) for x in lst] [11124864, 11124864, 11124864]
这表明所有三个引用都引用同一对象。请注意,发生这种情况 确实很 合理1。它只是复制 值 ,在这种情况下,这些值 是
引用。这就是为什么您看到同一参考重复了三遍的原因。有趣的是,如果我这样做
lst = [[]]*3 lst[0] = [5] lst[0].append(3)
然后单元格0的“链接”被破坏了,我得到了
[[5,3],[],[]]
,但lst[1].append(0)
仍然会导致[[5,3],[0],[0]
。您更改了占用的参考
lst[0]
;也就是说,你分配一个新的 值 来lst[0]
。但是您没有更改其他元素的 值
,它们仍然引用与它们所引用的对象相同的对象。并且lst[1]
并且lst[2]
仍然指的是完全相同的实例,因此,当然将项目附加到也会lst[1]
导致lst[2]
该更改。这是人们使用指针和引用犯的一个经典错误。这是简单的类比。你有一张纸。在上面写上某人房屋的地址。现在,您拿起那张纸,并将其影印两次,以便最终得到三张纸,上面写有相同的地址。现在,拿起
第一 张纸,写下上面写的地址,然后再写一个新地址到 别人的 房子里。另外两张纸上写的地址是否发生变化?不。那 正是 您的代码所做的。这就是
为什么 其他两项不变的原因。进一步,假设地址 仍然 是房屋的所有者 __在第二张纸上,为他们的房子建了一个附加车库。 现在我问你,地址在 第三
张纸上的房子是否有一个附加车库?是的,是的,因为它 和 地址写在 第二 张纸上的房子 完全 一样。这说明了有关第二个代码示例的 所有 内容。1:您没想到Python会调用“复制构造函数”吗?uke