2016-12-30 55 views
0

我有以下代碼:避免RuntimeError用圓圈參考

class Cell(object): 
    def eval(self): 
     raise NotImplementedError 


class RefCell(Cell): 
    def __init__(self, cell=None): 
     self.next_cell = cell 

    def set_next(self, cell): 
     self.next_cell = cell 
     if self.next_cell: 
      try: 
       check = self.next_cell.eval() 
      except AttributeError: 
       pass 
      else: 
       if check == self: 
        raise Exception 

    def eval(self): 
     return self.next_cell.eval() 


c1 = RefCell() 
c2 = RefCell() 
c3 = RefCell() 
c4 = RefCell() 

c1.set_next(c2) 
c2.set_next(c3) 
c3.set_next(c4) 
c4.set_next(c2) 

我試圖避免RuntimeError我遇到的時候:

c4.set_next(c2) 

但我就是想不通我可以捕捉到圈子參考,並拋出我的一般例外,而不是我碰到這個:

RuntimeError: maximum recursion depth exceeded while calling a Python object 

我會ap預示着任何想法。

+0

'eval'背後的想法是什麼?您可以prolly將根父級作爲參數傳遞給它,並在'self == parent'時引發異常。 –

+0

只要控制流進入'RefCell'的'eval'方法,就沒有出路。你是否想要檢測循環引用? – Jasper

+0

@賈斯珀正好 –

回答

1

您可以將隨後調用處理的節點歷史記錄保存爲eval,並檢查在處理之前是否訪問了節點。

def eval(self, history=None): 
    if history and self in history: 
     raise Exception 
    # put eval logic here 
    history = history or {} 
    history.add(self) 
    self.next_cell.eval(history) 
+0

這似乎很pythonic。 – Jasper

+0

我想到了這種方式,但我想避免它,以避免將列表傳遞給每個eval,這也意味着RefCell的eval簽名與Cell的eval簽名不匹配。任何想法改善這個解決方案? –

+0

傳遞「列表」很便宜,不會爲每個調用複製。另外,重載方法的不同簽名對我來說似乎不算太壞。 – Jasper

0

也許你可以介紹一個屬性,默認爲False位設置爲true,如果一個細胞的eval()函數被調用。然後有eval函數引發異常:

def eval(self): 
    self.evaluated=True 
    if self.next_cell.evaluated: 
     raise Exception 
    return self.next_cell.eval() 

我還沒試過,但它應該工作,我認爲。也不知道是否需要返回語句,因爲我不知道稍後您的腳本中應該發生什麼。

當然,您需要在下次嘗試評估時重置該屬性......這有點不方便。