因此,如果我有一个列表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': {...}}
这可能是将列表存储在最后一个元素中并修改其他元素的一种好方法,但是这种方法行不通,因为在每个递归引用中都会看到更改。
我知道为什么会这样,即由于它们的可变性。但是,我对这种行为的实际用例感兴趣。有人可以启发我吗?
用例是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版本(您想使用新鲜的解释器,这有点怪异):
>>> 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': {}}
由于此有序dict为空,因此根引用自身:
>>> 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
循环链接列表使更改键顺序变得容易,而不必重建整个基础哈希表。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句