2017-05-21 14 views
-2

Die Klasse Link wird verwendet, verkettete Listen zu erstellen und bearbeiten:Wie __add__ in diesem Fall richtig überschreiben?

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) 

von __repr__ imitiert ich eine __add__ Funktion implementieren möchten:

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

aber es funktioniert nicht und gibt mir eine solche Fehler (Der tatsächliche Dateipfad ist ausgeblendet):

>>> 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 

Also habe ich die letzte Zeile vongeändertzu:

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

und diese Zeit wird der Fehler:

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

Dann ich die __add__ Methode in der Klasse gelöscht, und versucht, einen anderen Weg:

zuerst die folgende Funktion an das Modul hinzuzufügen :

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

und im Terminal:

>>> 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)))))) 

Warum Link.__add__ = extend_link funktioniert, aber zwingende __add__ in der Klasse nicht?

PS: Das Beispiel ist von here

+1

Was ist 'add'? Es beschwert sich eindeutig über die fehlende "add" -Funktion. –

Antwort

0

Der erste Fehler, den Sie ist erhalten aufgrund der Tatsache, dass add existiert nicht.

Sie überschreiben __add__ in Ihrer Klasse, was dem Überschreiben des Operators + entspricht. Daher sollte add(self.rest, other) nur self.rest + other sein.

Der Operator + sucht nach der __add__ Methode des linken Mitglieds und ruft sie auf, wenn sie existiert. Deshalb funktioniert self.rest.__add__(other) auch. Der Grund für die Neudefinition von __add__ ist jedoch, + direkt verwenden zu können, so dass __add__ niemals unter diesem Namen aufgerufen werden sollte.

Jetzt ist der zweite Fehler, den Sie bekommen, ein bisschen komplizierter. Es besagt eindeutig, dass Sie versuchen, eine Link Instanz und eine tuple Instanz hinzuzufügen, die nicht definiert ist. Ein wenig Nachforschung führte mich dazu, dass an einem Punkt self.rest gleich empty ist. Aber empty ist als () definiert, die eine tuple ist.

Die einfachste Lösung, um dies in Ihrer __add__ Definition zu überprüfen, ob eines der Mitglieder zu empty gleich ist, und schicken Sie das richtige Ergebnis, ohne+ aufrufen. Das haben Sie in Ihrer extend_link Funktion gemacht.

Eine bessere Lösung wäre, Ihre empty zu bauen, um es zu einer Link Instanz zu machen.

Verwandte Themen