首页 > 解决方案 > 列表中是否使用了自引用列表或循环引用,例如。将列表附加到自身

问题描述

因此,如果我有一个列表a并附a加到它,我将得到一个包含它自己的引用的列表。

>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>> a[-1][-1][-1]
[1, 2, [...]]

这基本上会导致看似无限的递归。

不仅在列表中,在字典中也是如此:

>>> b = {'a':1,'b':2}
>>> b['c'] = b
>>> b
{'a': 1, 'b': 2, 'c': {...}}

将列表存储在最后一个元素中并修改其他元素可能是一种好方法,但这不起作用,因为在每个递归引用中都会看到更改。

我明白为什么会发生这种情况,即由于它们的可变性。但是,我对这种行为的实际用例感兴趣。有人可以启发我吗?

标签: pythonlistdictionarycircular-referencecircular-list

解决方案


用例是 Python 是一种动态类型语言,任何东西都可以引用任何东西,包括它自己。

列表元素是对其他对象的引用,就像变量名和属性以及字典中的键和值一样。引用没有类型,变量或列表不限于仅引用,例如整数或浮点值。每个引用都可以引用任何有效的 Python 对象。(Python 也是强类型的,因为对象有一个特定的类型,它不会改变;字符串仍然是字符串,列表仍然是列表)。

因此,因为 Python 是动态类型的,所以如下:

foo = []
# ...
foo = False

是有效的,因为foo不限于特定类型的对象,Python 列表对象也是如此。

当您的语言允许这样做时,您必须考虑递归结构,因为允许容器直接或间接地引用自己。当list您执行此操作并要求字符串表示时,表示通过不爆炸来考虑这一点。[...]当存在循环引用时,它会向您显示一个条目。这不仅适用于直接引用,您也可以创建间接引用:

>>> foo = []
>>> bar = []
>>> foo.append(bar)
>>> bar.append(foo)
>>> foo
[[[...]]]

foo是最外面的[/ ]] 对和条目[...]bar是中间的[/]对。

在许多实际情况下,您需要一个自引用(循环)结构。例如,内置OrderedDict对象使用循环链表来跟踪项目顺序。这通常不容易看到,因为该类型有 C 优化版本,但我们可以强制 Python 解释器使用纯 Python 版本(你想使用新的解释器,这有点 hackish):

>>> import sys
>>> class ImportFailedModule:
...     def __getattr__(self, name):
...         raise ImportError
...
>>> sys.modules["_collections"] = ImportFailedModule()  # block the extension module from being loaded
>>> del sys.modules["collections"]  # force a re-import
>>> from collections import OrderedDict

现在我们有了一个可以自省的纯 python 版本:

>>> od = OrderedDict()
>>> vars(od)
{'_OrderedDict__hardroot': <collections._Link object at 0x10a854e00>, '_OrderedDict__root': <weakproxy at 0x10a861130 to _Link at 0x10a854e00>, '_OrderedDict__map': {}}

因为这个有序的字典是空的,所以根引用了它自己:

>>> od._OrderedDict__root.next is od._OrderedDict__root
True

就像列表可以引用自身一样。添加一个或两个键,链表会增长,但最终仍然链接到自身:

>>> od["foo"] = "bar"
>>> od._OrderedDict__root.next is od._OrderedDict__root
False
>>> od._OrderedDict__root.next.next is od._OrderedDict__root
True
>>> od["spam"] = 42
>>> od._OrderedDict__root.next.next is od._OrderedDict__root
False
>>> od._OrderedDict__root.next.next.next is od._OrderedDict__root
True

循环链表可以轻松更改键顺序,而无需重建整个底层哈希表。


推荐阅读