当我使用切片语法“ mylist [:] = [mylist,mylist,...]”将带有自我引用的列表分配给列表副本时会发生什么情况?

时间:2018-11-28 17:20:07

标签: python python-3.x list assignment-operator

当我偶然发现以下代码片段时,我只是在看functools.lru_cache的实现:

root = []  # root of the circular doubly linked list
root[:] = [root, root, None, None]  # initialize by pointing to self

我熟悉圆形和双向链表。我也知道new_list = my_list[:]创建了my_list的副本。 当寻找切片分配或圆形双向链表的其他实现时,我找不到关于此特定语法的任何更多信息。

问题:

  1. 在这种情况下发生了什么。
  2. 是否可以使用不同的语法来达到相同的结果?
  3. some_list[:] = some_iterable是否有不同的常见用例(没有自我参考)?

3 个答案:

答案 0 :(得分:5)

root[:] = [root, root, None, None]

左手切片分配只是说root的引用被重新使用来保存右部分的内容。

因此root引用永远不会改变,是的,您可以在列表中引用自己(但不要尝试对它们进行递归展平:)。在这种情况下,表示形式将显示“列表上的递归”。

>>> root
[<Recursion on list with id=48987464>,
 <Recursion on list with id=48987464>,
 None,
 None]

打印并显示省略号:

>>> print(root)
[[...], [...], None, None]

请注意,您不需要为此分配切片。有一些触发递归的简单方法:

>>> root = []
>>> root.append(root)
>>> root
[<Recursion on list with id=51459656>]
>>> 

使用append不会更改引用,众所周知,它只是对列表进行了变异,为其自身添加了引用。也许更容易理解。

答案 1 :(得分:2)

  1. 在这种情况下怎么回事?

如果列表为l,则将调用l[:] = items的呼叫l.__setitem__(slice(None), items)。清除后,此方法会将给定迭代器中的各个项目分配给列表。

  1. 是否可以使用不同的语法来达到相同的结果?

你可以做

l.clear()
l.extend(items)
  1. some_list[:] = some_iterable (without the self reference)?是否有不同的常见用例

理论上,您可以将任何可迭代项放入列表中。

答案 2 :(得分:1)

只需查看反汇编的代码:

In [1]: def initializer():
   ...:     root = []  # root of the circular doubly linked list
   ...:     root[:] = [root, root, None, None]
   ...:     

In [2]: 

In [2]: import dis

In [3]: dis.dis(initializer)
  2           0 BUILD_LIST               0
              2 STORE_FAST               0 (root)

  3           4 LOAD_FAST                0 (root)
              6 LOAD_FAST                0 (root)
              8 LOAD_CONST               0 (None)
             10 LOAD_CONST               0 (None)
             12 BUILD_LIST               4
             14 LOAD_FAST                0 (root)
             16 LOAD_CONST               0 (None)
             18 LOAD_CONST               0 (None)
             20 BUILD_SLICE              2
             22 STORE_SUBSCR
             24 LOAD_CONST               0 (None)
             26 RETURN_VALUE

您要寻找的是STORE_SUBSCR操作码,可用来实现以下目的:

mplements TOS1[TOS] = TOS2

由于do文档是就地操作的原因。而且,如果您想知道什么是就地操作,请按以下步骤定义文档:

  

就地操作类似于二进制操作,因为它们删除了TOS和TOS1,并将结果推回堆栈,但是当TOS1支持它时,就地完成了操作,结果TOS可能是(但是不必是原始的TOS1。

这将验证源代码中的嵌入式文档所说的内容:

  

通过指向自我进行初始化。

关于您的其他问题:

  

是否可以使用不同的语法来达到相同的结果?

是的,您可以按照其他答案中的说明清除并使用list.extend属性设置列表项。或一一分配项目,也许哈哈

  

some_list [:]是否有其他常用用例=   some_iterable(没有自我参考)?

这是一个非常模糊的问题,因为它是什么。以内射方式分配项目,这可能具有替换项目而无需重新创建引用等的好处。

相关问题