2010-05-18 80 views
12

我已經用Python寫的容器類型和我想寫一個強大__repr__方法能夠正確處理這樣的容器包含本身的情況。如何處理Python中的遞歸repr()?

例如,這裏就是內置list做:用C語言編寫的CPython的

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

容器類型可以通過使用Py_ReprEnterPy_ReprLeave實現這一功能。純Python中是否有等價的功能,還是我需要創建自己的?

回答

6

你可以創建自己的,但是如果你想正確地做到這一點有點痛苦:你不應該在對象本身存儲'正在重新編號'標記標記,因爲這不是線程安全的。相反,您可以存儲正在重新編譯的實例的線程本地集合。

更便宜的解決方案是依賴於內置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) 
+0

不幸的是,我必須動態地計算再版字符串,所以我不能依賴於你描述的方式內置的再版()。我如何創建一個線程本地實例集? – 2010-05-18 16:36:30

+0

@DanielStutzbach,爲什麼包裹在try/finally塊? – akaRem 2013-05-25 10:51:25

+1

@akaRem:'self.something'是涉及遞歸的一些更復雜工作的佔位符。在糟糕的一天裏,有些東西可能會導致異常。如果出現這種情況,我們要確保'reprs'列表的方式清除出去回來了,否則會積累實例作爲錯誤堆積起來,造成越來越多的'MyThing's渲染爲'MyThing(...) '即使沒有遞歸。 – bobince 2013-05-26 09:34:22