2017-11-11 3 views
0

Angenommen, ich möchte den folgenden Code ausführen Python 3.6.3:Kopieren 'spezielle' Methoden in Python 3.x

class Foo: 
    def bar(self): 
     return 1 

    def __len__(self): 
     return 2 

class FooWrapper: 
    def __init__(self, foo): 
     self.bar = foo.bar 
     self.__len__ = foo.__len__ 



f = Foo() 
print(f.bar()) 
print(f.__len__()) 
print(len(f)) 

w = FooWrapper(Foo()) 
print(w.bar()) 
print(w.__len__()) 
print(len(w)) 

Hier ist die Ausgabe:

1 
2 
2 
1 
2 
TypeError: object of type 'FooWrapper' has no len() 

So __len__() funktioniert, aber len() nicht? Was gibt und wie gehe ich richtig kopieren __len__ methode von Foo bis FooWrapper?

By the way, ist das folgende Verhalten universell für alle ‚spezielle‘ Methoden, nicht nur __len__: zum Beispiel __iter__ oder __getitem__ nicht funktionieren entweder (sofern dies nicht direkt genannt)

Antwort

2

Der Grund, warum dies passiert ist, weil die Spezielle Methoden müssen sich auf die Klasse eines Objekts und nicht auf die Instanz beziehen.

len wird nach __len__ in der FooWrapper Klasse suchen. BTW, obwohl dies so aussieht, als ob es "funktioniert", fügen Sie tatsächlich foo.__len__ hinzu, d. H. Das bereits an die foo -Instanz von Foo gebundene Verfahren an Ihr FooWrapper Objekt. Das könnte die Absicht sein, aber Sie müssen sich dessen bewusst sein.

Der einfachste Weg, dies zu arbeiten ist zu FooWrapper selbst machen eine __len__ Methode, die __len__ der umhüllte Instanz rufen:

class FooWrapper: 
    def __init__(self, foo): 
     self.foo = foo 
     self.bar = foo.bar 
     self.__len__ = foo.__len__ 
    def __len__(self): 
     return len(self.foo) 

dass hace, dass für jede und alle speziellen Methoden explizit bedeutet existieren in die Wrapper-Klasse? Ja, tut es - und es ist einer der Schmerzen für die Erstellung von Proxies, die sich genauso verhalten wie das umhüllte Objekt.

Das ist, weil die speziellen Methoden für Existenz und Aufruf direkt in C getan werden, und nicht Python lange Lookup-Mechanismen verwenden, da tat wäre zu ineffizient.

Es ist möglich, eine Wrapper-Klasse Factory-Sache zu erstellen, die das Objekt untersuchen und eine brandneue Wrapperklasse mit allen sinnvollen Spezialmethoden erstellen würde - aber ich denke, das wäre zu weit fortgeschritten für das, was Sie haben denk jetzt nach.

Sie sollten nur explizite spezielle Methoden oder expliziten Zugriff auf das umschlossene Objekt im Rest des Codes verwenden. (Wenn Sie z. B. __iter__ von einem umgebrochenen Objekt verwenden müssen, statt for x in wrapper, tun Sie for x in wrapper.wrapped)