编程语言
首页 > 编程语言> > python – 使用乘法(*)意外行为生成子列表

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],[],[]], but lst[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