当我使用切片语法`mylist[:]=[mylist,mylist,..]`将具有自引用的列表分配给列表副本时,会发生什



我正在研究functools.ru_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(没有自引用(是否有不同的常见用例

在中

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. 在这种情况下发生了什么

如果l是列表,则l[:] = items调用l.__setitem__(slice(None), items)。此方法在清除给定可迭代项之后,将其各自分配给列表。

  1. 是否有不同的语法来实现相同的结果

你可以做

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

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

只需查看已分解的代码:

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

这是由于做文件一个到位的操作。如果你想知道什么是就地操作,下面是文档如何定义的:

就地操作类似于二进制操作,它们删除TOS和TOS1,并将结果推回到堆栈上,但当TOS1支持该操作时,该操作会就地完成,生成的TOS可能是(但不一定是(原始TOS1。

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

通过指向self进行初始化。

关于您的其他问题:

是否有不同的语法来实现相同的结果?

是的,正如其他答案中提到的那样,您可以使用list.extend属性清除并设置列表项。或者一个接一个地分配项目,也许lol

some_list[:]是否有不同的常见用例=some_iterable(没有自引用(?

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

相关内容

最新更新