3

假设您执行以下操作:

a = [1]
a[0] = a

你最终得到a等于[[...]]。这里发生了什么?这个隐含定义的无限链是如何a引用a' 的[[...]]

4

3 回答 3

8

你什么也没看到:

>>> a = []
>>> a[:] = [a] * 4
>>> a
[[...], [...], [...], [...]]

如果您对它在 CPython 中的工作方式感兴趣,请参阅list_reprinlistobject.c和类似函数。基本上,任何可能打印自引用对象的函数都会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;
于 2013-04-06T10:05:50.057 回答
3

该列表包含对其自身的引用。这[[...]]是打印列表时呈现的方式。

该实现不遗余力地确保它不会以无限递归结束。它通过呈现对已打印为[...].

这使得它也可以与间接自引用一起使用:

>>> a = []
>>> b = [a]
>>> a.append(b)
>>> a
[[[...]]]
>>> b
[[[...]]]

如果你真的很好奇,你可以研究 CPython 的源代码。在 Python 2.7.3 中,相关代码位于Objects/listobject.c.

于 2013-04-06T09:53:37.090 回答
2

我们a == [a]这里有,所以理论上a应该打印为一个包含一个元素的列表,即a——即它本身就是一个包含一个元素的列表,它本身就是一个包含一个元素的列表,以此类推。或者在印刷品中:无限数量的[,然后是无限数量的]。相反,我们得到的事实[[...]]只是 Python 试图提供帮助,而不是实际打印无限数量的[.

于 2013-04-06T09:58:25.430 回答