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

时间:2010-05-18 15:57:43

标签: python

我在Python中编写了一个容器类型,我正在尝试编写一个健壮的__repr__方法,该方法可以正确处理容器包含自身的情况。

例如,这是内置list的作用:

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

使用C语言为CPython编写的容器类型可以使用Py_ReprEnterPy_ReprLeave来实现此功能。在纯Python中是否有相同的功能,或者我是否需要创建自己的功能?

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:5)

如果您使用的是Python 3,则可以使用reprlib.recursive_repr装饰器。