2016-07-10 13 views
1

Ich habe die folgende Klasse:Wie verwendet man __getattr__, um zu attributierende Methoden zu delegieren?

class MyInt: 
    def __init__(self, v): 
     if type(v) != int: 
      raise ValueError('value must be an int') 
     self.v = v 

    def __getattr__(self, attr): 
     return getattr(self.v, attr) 

i = MyInt(0) 
print(i + 1) 

ich den Fehler: TypeError: unsupported operand type(s) for +: 'MyInt' and 'int'

Sollte i.__add__(1) nicht genannt werden? Und sollte nicht __getattr__ aufgerufen werden, wenn keine solche Methode in der MyInt Klasse gefunden wird?

+2

[Zusätzlich zur Umgehung beliebiger Instanzattribute aus Gründen der Korrektheit umgeht die implizite spezielle Methodensuche in der Regel auch die Methode '__getattribute __()' selbst der Metaklasse des Objekts. (Https://docs.python.org/3/ reference/datamodel.html # special-method-lookup) –

Antwort

3

__getattr__ kann nicht verwendet werden, um andere magische Methoden zu generieren. Sie müssen alle einzeln implementieren.

Wenn die Python-Sprache Internalitäten magische Methoden wie __add__ nachschlagen, umgehen sie __getattr__, __getattribute__ und die Instanz dict. Der Nachschlag geht ungefähr so ​​

def find_magic_method(object, method_name): 
    for klass in type(object).__mro__: 
     if method_name in klass.__dict__: 
      return klass.__dict__[method_name] 
    raise AttributeError 

Wenn Sie das genaue Lookup-Verfahren sehen wollen, es ist _PyObject_LookupSpecial in Objects/typeobject.c.

Wenn Sie sich fragen, warum Python dies tut, gibt es viele magische Methoden, für die es wirklich peinlich oder unmöglich wäre, das zu tun, was Sie erwartet haben. Zum Beispiel könnte Python möglicherweise __getattribute__ nicht verwenden, um __getattribute__ nachzuschlagen, da dies eine unendliche Rekursion ohne Basisfall verursachen würde.

+1

Der Unterschied zwischen dem echten Lookup und diesem Python-Code besteht darin, dass der obige Python-Code mit Metaklassen manipuliert werden kann, um ein benutzerdefiniertes '__dict__' zu liefern, während das eigentliche Lookup sogar umgeht die Metaklasse und greift über das direkte Feld in der zugrundeliegenden C-Struktur auf das '__dict__'-Mapping zu. – Bakuriu

+0

Das ist eine lange Datei. Könnten Sie mir bitte eine Zeilennummer oder einen Funktionsnamen geben? –

+1

@ JonMcClung: Der Link geht direkt auf die Funktion, und ich sagte, der Funktionsname ist '_PyObject_LookupSpecial'. Die meisten Helfer, auf die es angewiesen ist, befinden sich in derselben Datei, daher sollten Sie sie mit Strg-F finden können. – user2357112

Verwandte Themen