python – 使用乘法(*)意外行为生成子列表
作者:互联网
参见英文答案 > List of lists changes reflected across sublists unexpectedly 12个
> Nested List Indices 2个
我确信这已在某个地方得到解答,但我不确定如何描述它.
假设我想创建一个包含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存储对单个单元格的引用……?
解决方法:
My best guess is that using multiplication in the form
[[]] * x
causes Python to store a reference to a single cell…?
是.你可以自己测试一下
>>> lst = [[]] * 3
>>> print [id(x) for x in lst]
[11124864, 11124864, 11124864]
这表明所有三个引用都引用同一个对象.请注意,发生这种情况真的很有意义1.它只是复制值,在这种情况下,值是引用.这就是为什么你看到相同的参考重复三次.
It is interesting to note that if I do
lst = [[]]*3
lst[0] = [5]
lst[0].append(3)
then the ‘linkage’ of cell 0 is broken and I get
[[5,3],[],[]]
, butlst[1].append(0)
still causes[[5,3],[0],[0]
.
你改变了占用lst [0]的引用;也就是说,您为lst [0]分配了一个新值.但是你没有改变其他元素的值,它们仍然引用他们引用的同一个对象.并且lst [1]和lst [2]仍然引用完全相同的实例,因此当然将项添加到lst [1]会导致lst [2]也看到该更改.
这是人们用指针和引用做出的经典错误.这是简单的类比.你有一张纸.在它上面,你写了某人家的地址.你现在拿走那张纸,然后复印两次,这样你就会得到三张纸,上面写着相同的地址.现在,拿第一张纸,涂上写在上面的地址,并写一个新地址给别人家.写在另外两张纸上的地址是否有变化?不,这正是你的代码所做的.这就是为什么其他两个项目不会改变的原因.此外,想象一下,仍然在第二张纸上的房子的主人为他们的房子建造了一个附加车库.现在我问你,那个地址在第三张纸上的房子是否有一个附加车库?是的,确实如此,因为它与在第二张纸上写的地址完全一样.这解释了关于第二个代码示例的所有内容
1:你没想到Python会调用“复制构造函数”吗?普科.
标签:nested-lists,python,list,mutable 来源: https://codeday.me/bug/20190916/1807757.html