内置类型的问题——重复增加一个层次的深度

未匹配的标注

重复序列就像把它自己添加到自己许多次。然而,当可变序列被嵌套时,效果可能不总是你预期的那样。比如,下面例子中将L重复4次分配给X,而包含L的列表再重复4次后分配给Y:

>>> L = [4, 5, 6]
>>> X = L * 4 # Like [4, 5, 6] + [4, 5, 6] + ...
>>> Y = [L] * 4 # [L] + [L] + ... = [L, L,...]
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]

因为L被嵌套在第二次重复中,Y最后嵌套了指回分配给L的原来的列表的引用,所以就会受到前面一节中提到的同样的副作用的影响:

>>> L[1] = 0 # Impacts Y but not X
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 0, 6], [4, 0, 6], [4, 0, 6], [4, 0, 6]]

这可能看起来是人为的且不实用——直到它在你的代码中不经意地出现!这个问题的解法和前一节中的一样,因为这其实只是创建共享可变对象引用例子的另一种方式——当你不想要共享引用时,就创建拷贝:

>>> L = [4, 5, 6]
>>> Y = [list(L)] * 4 # Embed a (shared) copy of L
>>> L[1] = 0
>>> Y
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]

甚至更微妙地,虽然Y不再和L共享对象,但它仍然嵌入了指向它的同一个拷贝的四份引用。如果还必须避免这种共享,就要确保每个嵌入的拷贝是独一无二的:

>>> Y[0][1] = 99 # All four copies are still the same
>>> Y
[[4, 99, 6], [4, 99, 6], [4, 99, 6], [4, 99, 6]]
>>> L = [4, 5, 6]
>>> Y = [list(L) for i in range(4)]
>>> Y
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]
>>> Y[0][1] = 99
>>> Y
[[4, 99, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]

如果记得重复、连接、切片都只拷贝它们的操作数对象的顶层,这些例子就会好理解得多。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~