2017-05-21 44 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实例。