我已經用Python寫的容器類型和我想寫一個強大__repr__
方法能夠正確處理這樣的容器包含本身的情況。如何處理Python中的遞歸repr()?
例如,這裏就是內置list
做:用C語言編寫的CPython的
>>> x = []
>>> x.append(x)
>>> repr(x)
'[[...]]'
容器類型可以通過使用Py_ReprEnter
和Py_ReprLeave
實現這一功能。純Python中是否有等價的功能,還是我需要創建自己的?
我已經用Python寫的容器類型和我想寫一個強大__repr__
方法能夠正確處理這樣的容器包含本身的情況。如何處理Python中的遞歸repr()?
例如,這裏就是內置list
做:用C語言編寫的CPython的
>>> x = []
>>> x.append(x)
>>> repr(x)
'[[...]]'
容器類型可以通過使用Py_ReprEnter
和Py_ReprLeave
實現這一功能。純Python中是否有等價的功能,還是我需要創建自己的?
你可以創建自己的,但是如果你想正確地做到這一點有點痛苦:你不應該在對象本身存儲'正在重新編號'標記標記,因爲這不是線程安全的。相反,您可以存儲正在重新編譯的實例的線程本地集合。
更便宜的解決方案是依賴於內置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)
如果你使用Python 3,你可以使用reprlib.recursive_repr裝飾的。
不幸的是,我必須動態地計算再版字符串,所以我不能依賴於你描述的方式內置的再版()。我如何創建一個線程本地實例集? – 2010-05-18 16:36:30
@DanielStutzbach,爲什麼包裹在try/finally塊? – akaRem 2013-05-25 10:51:25
@akaRem:'self.something'是涉及遞歸的一些更復雜工作的佔位符。在糟糕的一天裏,有些東西可能會導致異常。如果出現這種情況,我們要確保'reprs'列表的方式清除出去回來了,否則會積累實例作爲錯誤堆積起來,造成越來越多的'MyThing's渲染爲'MyThing(...) '即使沒有遞歸。 – bobince 2013-05-26 09:34:22