2010-08-05 3 views
7

Dies ist das erste Mal, dass ich hier schreibe, tut mir leid, wenn die Nachricht nicht oder zu lange ist.Asymmetrisches Verhalten für __getattr__, newstyle vs oldstyle Klassen

Ich war daran interessiert, mehr darüber zu erfahren, wie Objekte Attribute bei Bedarf abgerufen werden. Also lese ich die Python 2.7 Dokumentation mit dem Titel "Data Model" here, traf ich __getattr__ und, um zu überprüfen, ob ich sein Verhalten verstanden oder nicht, schrieb ich diese einfachen (und unvollständigen) String-Wrapper.

class OldStr: 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

class NewStr(object): 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

Wie Sie sie sind gleich, mit Ausnahme ist, um eine Oldstyle vs newstyle Klassen sehen. Da der zitierte Text sagt __getattr__ ist "aufgerufen, wenn eine Attributsuche das Attribut an den üblichen Orten nicht gefunden hat", wollte ich versuchen, eine + Operation auf zwei Instanzen dieser Klassen zu sehen, was passiert ist, erwartet ein identisches Verhalten.

Aber die Ergebnisse, die ich mich ein wenig verwirrt habe:

>>> x=OldStr("test") 
>>> x+x 
method __getattr__, attribute requested __coerce__ 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: 'NoneType' object is not callable 

gut! Ich habe keine Methode für __coerce__ definiert (obwohl ich eine Anfrage für __add__ erwartet habe, vergiss :), also wurde __getattr__ beteiligt und gab eine nutzlose Sache zurück. Aber dann

>>> y=NewStr("test") 
>>> y+y 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'NewStr' and 'NewStr' 

Warum dieses asymmetrische Verhalten zwischen __getattr__ in Oldstyle-Klassen und newstyle diejenigen, wenn ein Einbau-Operator wie + verwenden? Könnte mir jemand bitte helfen, zu verstehen, was vor sich geht, und was war mein Fehler beim Lesen der Dokumentation?

Vielen Dank, Ihre Hilfe wird sehr geschätzt!

+6

Bitte verwenden Sie keine alten Stilklassen für irgendetwas. Sie sind aus offensichtlichen Gründen veraltet - wie dieser. Da sie veraltet sind, ist es nicht hilfreich, zu wissen, wie sie früher gearbeitet haben. Verwerfe sie und gehe bitte weiter. –

+3

Vergleichen Sie das Verhalten von alten und neuen Klassen, um zu veranschaulichen, wie die neuen Stilklassen funktionieren, vor allem, wenn Sie mit Klassen im alten Stil vertraut sind. Es ist in der Tat nicht überraschend, dass sie auf unterschiedliche Weise arbeiten, und es ist beruhigend zu wissen, dass die neuen Klassen wie erwartet funktionieren. Dennoch ist es sinnvoll, zu verstehen, warum Code so interpretiert wird, wie er ist, unabhängig von der Version. –

Antwort

2

Ihre __getattr__ Funktionen geben nichts zurück. Ich weiß nicht, warum die Old-Style-Klasse macht die __getattr__ vor der Suche nach __add__, aber es ist, und dies versucht, den Rückgabewert zu rufen, die None ist.

Die neue Stil-Klasse macht es richtig: Sie haben __add__ nicht definiert, so dass es nicht weiß, wie Sie sie hinzufügen.

4

Special method lookup for new-style classes See.

Spezielle Methoden werden direkt im Klassenobjekt nachgeschlagen, die Instanzobjekte und somit __getattr__() und __getattribute__() werden überbrückt. Aus genau dem gleichen Grund funktioniert instance.__add__ = foobar nicht.

Dies wird getan, um den Zugriff auf Attribute zu beschleunigen. Spezielle Methoden werden sehr häufig aufgerufen, und wenn sie dem Standard unterworfen werden, würde eine ziemlich komplexe Attributsuche den Interpreter erheblich verlangsamen.

Das Attribut Lookup für Old-Style-Klassen ist viel weniger komplex (vor allem alte Stilklassen unterstützen keine Deskriptoren), so dass es keinen Grund gibt, spezielle Methoden in alten Style-Klassen anders zu behandeln.

Verwandte Themen