假设您执行以下操作:
a = [1]
a[0] = a
最终a
等于[[...]]
。这里发生了什么?这个隐含定义的a
无限链指向a
的结果如何最终为[[...]]
?
答案 0 :(得分:6)
你什么都不见:
>>> a = []
>>> a[:] = [a] * 4
>>> a
[[...], [...], [...], [...]]
如果您对CPython的工作原理感兴趣,请参阅list_repr
in listobject.c
和类似的功能。基本上,任何可能打印自引用对象的函数在打印对象之前调用Py_ReprEnter
,并在完成时调用Py_ReprLeave
。 (参见object.c
for the definitions of these functions。)前者检查对象是否在当前正在打印的线程局部对象堆栈中找到(如果没有,则推送它);后者从堆栈中弹出对象。因此,如果Python正在打印列表并发现列表在堆栈上,那必须意味着这是一个自引用列表,并且列表应该缩写,以避免无限循环:
i = Py_ReprEnter((PyObject*)v);
if (i != 0) {
return i > 0 ? PyString_FromString("[...]") : NULL;
}
// ...
Py_ReprLeave((PyObject *)v);
return result;
答案 1 :(得分:3)
该列表包含对自身的引用。 [[...]]
是打印列表时的呈现方式。
该实现不遗余力地确保它不会以无限递归结束。它通过渲染对已经打印为[...]
的对象的引用来实现。
这使得它也适用于间接自引用:
>>> a = []
>>> b = [a]
>>> a.append(b)
>>> a
[[[...]]]
>>> b
[[[...]]]
如果你真的很好奇,你可以学习CPython的源代码。在Python 2.7.3中,相关代码位于Objects/listobject.c
。
答案 2 :(得分:2)
我们这里有a == [a]
,所以理论上a
应该打印成一个包含一个元素的列表,即a
---即它本身就是一个包含一个元素的列表,这是本身是一个包含一个元素的列表,依此类推。或者在印刷品中:无限数量的[
,后跟无限数量的]
。我们得到[[...]]
的事实只是Python试图提供帮助而不是实际打印无限数量的[
。