这个MWE在过去会导致堆栈溢出,因为x
引用引用x
的y
:
class Ref:
def __init__(self, name):
self.name = name
self.value = None
def __repr__(self):
if self.value is None:
return self.name
return f"{self.name}={self.value!r}"
if __name__ == '__main__':
x, y = Ref("x"), Ref("y")
x.value = (1, y)
y.value = (2, x)
print(x)
print(y)
但是当我用CPython 3.10.4测试它时,它可以开箱即用!
x=(1, y=(2, x=(...)))
y=(2, x=(1, y=(...)))
我找不到这个行为是什么时候改变的。我最近在2020年看到了几个问题,想知道如何处理相互递归或自递归的数据结构。我还发现reprlib
内置库产生类似的输出,所以我怀疑一些语言开发人员决定默认使用它。
注意:我也测试了它与__str__
,它也工作,所以它不是特定于repr()
。
它实际上从来没有真正做到过,直到今天(版本3.12.0 alpha 0)。
您展示的例子是最简单的一个:递归repr
与同一个类的实例。在这种情况下,解释器很容易检测到repr
将导致无限递归,因此停止并产生...
:它只需要检查当前类的.__repr__()
方法是否正在请求同一类实例的.__repr__()
。
自Python 1.5.1(1998!)以来一直支持,如Misc/HISTORY
所示:
========================================
==> Release 1.5.1 (October 31, 1998) <==
========================================
[...]
- No longer a core dump when attempting to print (or repr(), or str())
a list or dictionary that contains an instance of itself; instead, the
recursive entry is printed as [...] or {...}. See Py_ReprEnter() and
Py_ReprLeave() below. Comparisons of such objects still go beserk,
since this requires a different kind of fix; fortunately, this is a
less common scenario in practice.
即使在最新的CPython版本上,任何稍微复杂的情况仍然会导致问题:
class A:
def __init__(self):
self.value = None
def __repr__(self):
return f"{self.value!r}"
class B:
def __init__(self):
self.value = None
def __repr__(self):
return f"{self.value!r}"
a, b = A(), B()
a.value = b
b.value = a
print(a)
# RecursionError: maximum recursion depth exceeded while getting the repr of an object