假设你做以下操作:
a = [1]
a[0] = a
你最终得到
a
和 [[...]]
相等。这是怎么回事呢?这个隐式定义的无限链如何将指向 a
的 a
改为 [[...]]
呢?假设你做以下操作:
a = [1]
a[0] = a
a
和 [[...]]
相等。这是怎么回事呢?这个隐式定义的无限链如何将指向 a
的 a
改为 [[...]]
呢?你还没见过:
>>> a = []
>>> a[:] = [a] * 4
>>> a
[[...], [...], [...], [...]]
listobject.c
中的list_repr
和类似的函数。基本上,任何可能打印自引用对象的函数在打印之前都会调用Py_ReprEnter
,并在完成后调用Py_ReprLeave
。(有关这些函数的定义,请参见object.c
)。前者检查对象是否在线程本地对象栈中找到(如果没有,则将其推送);后者从堆栈中弹出对象。因此,如果Python正在打印列表并发现该列表在栈中,那么这必须意味着这是一个自引用列表,并且应该缩写该列表,以避免无限循环: i = Py_ReprEnter((PyObject*)v);
if (i != 0) {
return i > 0 ? PyString_FromString("[...]") : NULL;
}
// ...
Py_ReprLeave((PyObject *)v);
return result;
这个列表包含对它本身的引用。当你打印这个列表时,[[...]]
是如何呈现的。
实现过程会设法确保不会陷入无限递归。它通过将已经被打印的对象的引用渲染为[...]
来实现。
这使得它也可以处理间接自引用:
>>> a = []
>>> b = [a]
>>> a.append(b)
>>> a
[[[...]]]
>>> b
[[[...]]]
如果您真的很好奇,可以学习CPython的源代码。在Python 2.7.3中,相关的代码位于Objects/listobject.c
。
a
的方法最终会陷入无限递归。 - NPEa == [a]
,理论上来说,a
应该被打印为一个只包含一个元素的列表,即它本身也是一个只包含一个元素的列表,依此类推。或者说,在打印时,会有无限数量的 [
,后面跟着无限数量的 ]
。但实际上我们得到的是 [[...]]
,这是因为 Python 试图帮助我们,而不是真正地打印出无限数量的 [
。
[...]
是 Python 用来表示自引用字符串的方式。请参见 https://dev59.com/BW865IYBdhLWcg3wnP6a。 - Stecman