如何处理Python中的递归repr()?
我在Python里写了一个容器类型,现在想写一个可靠的__repr__
方法,确保它能正确处理容器里面包含它自己的情况。
比如,内置的list
是怎么做的:
>>> x = []
>>> x.append(x)
>>> repr(x)
'[[...]]'
用C语言为CPython写的容器类型可以通过Py_ReprEnter
和Py_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)