Gibt es in Python eine Möglichkeit, eine Klassenmethode auf Instanzebene zu überschreiben? Beispielsweise:
class Dog:
def bark(self):
print "WOOF"
boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
Bitte tun Sie dies nicht wie gezeigt. Ihr Code wird unlesbar, wenn Sie eine Instanz monkeypatchen, um sich von der Klasse zu unterscheiden.
Sie können monkeypatched Code nicht debuggen.
Wenn Sie einen Fehler in boby
und findenprint type(boby)
, werden Sie sehen, dass (a) es ein Hund ist, aber (b) aus einem unbekannten Grund nicht richtig bellt. Das ist ein Albtraum. TU es nicht.
Bitte machen Sie dies stattdessen.
class Dog:
def bark(self):
print "WOOF"
class BobyDog( Dog ):
def bark( self ):
print "WoOoOoF!!"
otherDog= Dog()
otherDog.bark() # WOOF
boby = BobyDog()
boby.bark() # WoOoOoF!!
Ja es ist möglich:
quelle
funcType
und warum dies erforderlich ist.funcType = types.MethodType
(nach dem Importierentypes
) anstelle von verwendet wirdfuncType = type(Dog.bark)
.__get__
die Funktion auch aufrufen , um sie an die Instanz zu binden.Sie müssen MethodType aus dem Typmodul verwenden. Zweck von MethodType ist das Überschreiben von Methoden auf Instanzebene (damit self in überschriebenen Methoden verfügbar ist).
siehe unten Beispiel.
quelle
Um die hervorragende Antwort von @ codelogic zu erklären, schlage ich einen expliziteren Ansatz vor. Dies ist die gleiche Technik wie die
.
Operator eine Klassenmethode gründlich bindet, wenn Sie als Instanzattribut darauf zugreifen, mit der Ausnahme, dass Ihre Methode tatsächlich eine außerhalb einer Klasse definierte Funktion ist.Bei der Arbeit mit dem Code von @ codelogic besteht der einzige Unterschied darin, wie die Methode gebunden ist. Ich verwende die Tatsache , dass die Funktionen und Methoden sind nicht-Daten - Deskriptoren in Python, und das Aufrufen von
__get__
Verfahren. Beachten Sie insbesondere, dass sowohl das Original als auch die Ersetzung identische Signaturen haben. Dies bedeutet, dass Sie die Ersetzung als vollständige Klassenmethode schreiben und über auf alle Instanzattribute zugreifen könnenself
.Durch Zuweisen der gebundenen Methode zu einem Instanzattribut haben Sie eine nahezu vollständige Simulation zum Überschreiben einer Methode erstellt. Eine praktische Funktion, die fehlt, ist der Zugriff auf die No-Arg-Version von
super
, da Sie sich nicht in einer Klassendefinition befinden. Eine andere Sache ist, dass das__name__
Attribut Ihrer gebundenen Methode nicht den Namen der Funktion annimmt, die es überschreibt, wie es in der Klassendefinition der Fall wäre, aber Sie können es trotzdem manuell festlegen. Der dritte Unterschied besteht darin, dass Ihre manuell gebundene Methode eine einfache Attributreferenz ist, die zufällig eine Funktion ist. Der.
Operator ruft lediglich diese Referenz ab. Beim Aufrufen einer regulären Methode von einer Instanz aus erstellt der Bindungsprozess jedes Mal eine neue gebundene Methode.Der einzige Grund, warum dies funktioniert, ist übrigens, dass Instanzattribute Nicht-Daten- Deskriptoren überschreiben . Datendeskriptoren haben
__set__
Methoden, die Methoden (zum Glück für Sie) nicht haben. Datendeskriptoren in der Klasse haben tatsächlich Vorrang vor allen Instanzattributen. Aus diesem Grund können Sie einer Eigenschaft zuweisen: Ihre__set__
Methode wird aufgerufen, wenn Sie versuchen, eine Zuweisung vorzunehmen. Ich persönlich gehe gerne noch einen Schritt weiter und verstecke den tatsächlichen Wert des zugrunde liegenden Attributs in der Instanz__dict__
, auf die mit normalen Mitteln nicht zugegriffen werden kann, gerade weil die Eigenschaft es beschattet.Sie sollten auch bedenken, dass dies für magische Methoden (doppelter Unterstrich) sinnlos ist . Magische Methoden können natürlich auf diese Weise überschrieben werden, aber die Operationen, die sie verwenden, betrachten nur den Typ. Sie können beispielsweise
__contains__
in Ihrer Instanz etwas Besonderes festlegen , aber ein Aufrufx in instance
würde dies ignorieren undtype(instance).__contains__(instance, x)
stattdessen verwenden. Dies gilt für alle im Python- Datenmodell angegebenen magischen Methoden .quelle
Sie können die
boby
Variable innerhalb der Funktion verwenden, wenn Sie dies benötigen. Da Sie die Methode nur für dieses eine Instanzobjekt überschreiben, ist dieser Weg einfacher und hat genau den gleichen Effekt wie die Verwendungself
.quelle
patching
und dies ist der richtige Weg, dies zu tun (zBboby = Dog()
undboby.bark = new_bark
). Es ist unglaublich nützlich beim Testen von Einheiten für Kontrollen. Weitere Erklärungen finden Sie unter tryolabs.com/blog/2013/07/05/run-time-method-patching-python (Beispiele) - nein, ich bin nicht mit der verlinkten Site oder dem verlinkten Autor verbunden.Da hier niemand erwähnt
functools.partial
:quelle
Da Funktionen in Python erstklassige Objekte sind, können Sie sie beim Initialisieren Ihres Klassenobjekts übergeben oder jederzeit für eine bestimmte Klasseninstanz überschreiben:
und die Ergebnisse sind
quelle
Obwohl mir die Vererbungsidee von S. Lott gefallen hat und ich der Sache 'Typ (a)' zustimme, denke ich, dass Funktionen auf folgende Weise verwaltet werden können:
und die Ausgabe ist:
quelle
Sehr geehrte Damen und Herren, dies wird nicht überschrieben. Sie rufen dieselbe Funktion nur zweimal mit dem Objekt auf. Grundsätzlich bezieht sich das Überschreiben auf mehr als eine Klasse. Wenn dieselbe Signaturmethode in verschiedenen Klassen vorhanden ist, entscheidet die Funktion, die Sie aufrufen, über das Objekt, das dies aufruft. Das Überschreiben ist in Python möglich, wenn Sie dafür sorgen, dass mehr als eine Klasse dieselben Funktionen schreibt und eine Sache mehr teilt, dass das Überladen in Python nicht zulässig ist
quelle
Ich fand, dass dies die genaueste Antwort auf die ursprüngliche Frage ist
https://stackoverflow.com/a/10829381/7640677
quelle