2017-05-21 74 views
-2

Link用於構建和操作鏈表:如何在這種情況下正確覆蓋__add__?

class Link: 
    """A linked list with a first element and the rest.""" 
    empty =() 

    def __init__(self, first, rest=empty): 
     assert rest is Link.empty or isinstance(rest, Link) 
     self.first = first 
     self.rest = rest 

    def __getitem__(self, i): 
     if i == 0: 
      return self.first 
     else: 
      return self.rest[i-1] 

    def __len__(self): 
     return 1 + len(self.rest) 

    def __repr__(self): 
     """Return a string that would evaluate to self.""" 
     if self.rest is Link.empty: 
      rest = '' 
     else: 
      rest = ', ' + repr(self.rest) 
     return 'Link({0}{1})'.format(self.first, rest) 

通過模仿__repr__我想要實現的功能__add__

def __add__(self, other): 
    if self is Link.empty: 
     return other 
    else: 
     return Link(self.first, add(self.rest, other)) 

但是它不工作,並給了我這樣的錯誤(實際的文件路徑是隱藏的):

>>> lst = Link(3, Link(4, Link(5))) 
>>> lst 
Link(3, Link(4, Link(5))) 
>>> lst + lst 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "PATH_TO_THE_FILE", line 31, in __add__ 
    return Link(self.first, add(self.rest, other)) 
NameError: name 'add' is not defined 

所以我改變了的最後一行到:

return Link(self.first, self.rest.__add__(other)) 

和此時的誤差變爲:

TypeError: can only concatenate tuple (not "Link") to tuple 

然後我在類刪除__add__方法並試圖另一種方式:

第一添加以下功能的模塊:

def extend_link(s, t): 
    if s is Link.empty: 
     return t 
    else: 
     return Link(s.first, extend_link(s.rest, t)) 

並在終端:

>>> lst = Link(3, Link(4, Link(5))) 
>>> Link.__add__ = extend_link 
>>> lst + lst 
Link(3, Link(4, Link(5, Link(3, Link(4, Link(5)))))) 

那麼,爲什麼Link.__add__ = extend_link的作品,但首要__add__在班上沒有?

PS:這個例子是從here

+1

什麼是「添加」?這顯然是抱怨缺少「添加」功能。 –

回答

0

你得到的第一個錯誤是由於這樣的事實:add不存在。

您在類中覆蓋__add__,這對應於覆蓋+運算符。因此,add(self.rest, other)應該只有self.rest + other

+運算符通過查找左邊成員的__add__方法,並在存在的情況下調用它。這就是爲什麼self.rest.__add__(other)也適用。但是,重新定義__add__的原因是爲了能夠直接使用+,所以__add__絕對不能在此名稱下調用。

現在,你得到的第二個錯誤是有點棘手。它清楚地表明您正試圖添加一個Link實例和一個未定義的tuple實例。有點調查使我發現,在某一點上,self.rest等於empty。但是empty被定義爲(),這是tuple

最簡單的修復程序,這是在你的__add__定義檢查成員之一等於empty,並返回正確的結果,沒有調用+。這就是你在你的extend_link函數中所做的。

更好的解決方法是構建您的empty以使其成爲Link實例。