如何处理Python中的递归repr()?

17 投票
2 回答
3707 浏览
提问于 2025-04-15 22:51

我在Python里写了一个容器类型,现在想写一个可靠的__repr__方法,确保它能正确处理容器里面包含它自己的情况。

比如,内置的list是怎么做的:

>>> x = []
>>> x.append(x)
>>> repr(x)
'[[...]]'

用C语言为CPython写的容器类型可以通过Py_ReprEnterPy_ReprLeave来实现这个功能。那么在纯Python中有没有类似的功能,还是说我需要自己来实现呢?

2 个回答

11

如果你在使用Python 3,可以利用一个叫做 reprlib.recursive_repr 的装饰器。

7

你可以自己创建一个,但如果想做好这件事会有点麻烦:你不应该把一个“正在表示”的标记存储在对象本身上,因为这样做在多线程环境下不安全。相反,你可以存储一个线程本地的实例集合,用来记录哪些实例正在被表示。

一个更简单的解决方案是依赖于内置的 repr,它可以处理递归问题,比如:

def __init__(self, *list):
    self._list= list
def __repr__(self):
    return 'mything('+repr(self._list)[1:-1]+')')

只要在递归循环中有 一个 对象触发了 Py_ReprEnter,那么 repr 就无法形成一个完整的循环。

我该如何创建一个线程本地的实例集合呢?

可以使用 threading 模块来实现:

class MyThing(object):
    _local= threading.local()
    _local.reprs= set()

    def __repr__(self):
        reprs= MyThing._local.reprs
        sid= id(self)
        if sid in reprs:
            return 'MyThing(...)'
        try:
            reprs.add(sid)
            return 'MyThing(%r)' % self.something
        finally:
            reprs.remove(sid)

撰写回答