2017-05-21 12 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

「追加」とはそれは明らかに 'add'関数の欠落について不平を言っています。 –

答えて

0

からあなたが得る最初のエラーがaddが存在しないという事実によるものです。

クラス内で__add__をオーバーライドします。これは、+演算子をオーバーライドすることに相当します。したがって、add(self.rest, other)self.rest + otherである必要があります。

+演算子は、左メンバーの__add__メソッドを探し、それが存在する場合はそれを呼び出します。そのため、self.rest.__add__(other)も同様です。ただし、__add__を再定義する理由は、+を直接使用できるため、__add__はこの名前で決して呼び出されるべきではありません。

ここで2番目のエラーは少しトリッキーです。これは、Linkインスタンスと定義されていないtupleインスタンスを追加しようとしていることを明確に示しています。ちょっと調べてみると、ある時点でself.restemptyに等しいという事実につながります。しかし、emptyは、tupleである()と定義されます。これに

最も簡単な修正は+を呼び出すずに、メンバーの一人がemptyに等しい場合は、あなたの__add__定義でチェックして、正しい結果を返すことです。これはあなたのextend_link機能で行ったことです。

より良い修正は、emptyを作成してLinkインスタンスにすることです。

関連する問題