A.W*_*Wan 11 python list mutable nested-lists
我确信这已在某个地方得到解答,但我不确定如何描述它.
假设我想创建一个包含3个空列表的列表,如下所示:
lst = [[], [], []]
Run Code Online (Sandbox Code Playgroud)
这样做我以为我很聪明:
lst = [[]] * 3
Run Code Online (Sandbox Code Playgroud)
但是我发现,在调试了一些奇怪的行为之后,这导致了对一个子列表的追加更新,比如lst[0].append(3),更新整个列表,[[3], [3], [3]]而不是[[3], [], []].
但是,如果我用列表初始化列表
lst = [[] for i in range(3)]
Run Code Online (Sandbox Code Playgroud)
然后做lst[1].append(5)了预期的[[], [5], []]
我的问题是为什么会发生这种情况?有趣的是,如果我这样做
lst = [[]]*3
lst[0] = [5]
lst[0].append(3)
Run Code Online (Sandbox Code Playgroud)
那么单元格0的"连接"就被打破了[[5,3],[],[]],但是我得到了,但lst[1].append(0)仍然会导致[[5,3],[0],[0].
我最好的猜测是在表单中使用乘法[[]]*x会导致Python存储对单个单元格的引用......?
jas*_*son 20
我最好的猜测是在表单中使用乘法
[[]] * x会导致Python存储对单个单元格的引用......?
是.你可以自己测试一下
>>> lst = [[]] * 3
>>> print [id(x) for x in lst]
[11124864, 11124864, 11124864]
Run Code Online (Sandbox Code Playgroud)
这表明所有三个引用都引用同一个对象.请注意,发生这种情况真的很有意义1.它只是复制值,在这种情况下,值是引用.这就是为什么你看到相同的参考重复三次.
有趣的是,如果我这样做
lst = [[]]*3
lst[0] = [5]
lst[0].append(3)
Run Code Online (Sandbox Code Playgroud)
那么单元格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会调用"复制构造函数"吗?普科.
这是因为序列乘法仅重复参考.在编写时[[]] * 2,您创建一个包含两个元素的新列表,但这两个元素在内存中都是相同的对象,即空列表.因此,一方的变化反映在另一方面.相比之下,理解在每次迭代中创建一个新的独立列表:
>>> l1 = [[]] * 2
>>> l2 = [[] for _ in xrange(2)]
>>> l1[0] is l1[1]
True
>>> l2[0] is l2[1]
False
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1357 次 |
| 最近记录: |