Was ist der Unterschied zwischen den folgenden Klassenmethoden?
Ist es so, dass einer statisch ist und der andere nicht?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
@classmethod
auf die Definition anwenden . Der erste Parameter solltecls
anstelle von aufgerufen werdenself
und empfängt das Klassenobjekt anstelle einer Instanz Ihrer Klasse:Test.method_three()
unda_test.method_three()
ist äquivalent.self
Argument erstellen ? Gibt es dafür einen starken Anwendungsfall?Antworten:
In Python wird zwischen gebundenen und ungebundenen Methoden unterschieden.
Grundsätzlich ein Aufruf einer Mitgliedsfunktion (wie
method_one
), einer gebundenen Funktionwird übersetzt in
dh ein Aufruf einer ungebundenen Methode. Aus diesem Grund schlägt ein Aufruf Ihrer Version von
method_two
mit a fehlTypeError
Sie können das Verhalten einer Methode mithilfe eines Dekorateurs ändern
Der Dekorateur weist die integrierte Standard-Metaklasse
type
(die Klasse einer Klasse, siehe diese Frage ) an, keine gebundenen Methoden für zu erstellenmethod_two
.Jetzt können Sie die statische Methode sowohl für eine Instanz als auch für die Klasse direkt aufrufen:
quelle
Methoden in Python sind eine sehr, sehr einfache Sache, wenn Sie die Grundlagen des Deskriptorsystems verstanden haben. Stellen Sie sich folgende Klasse vor:
Schauen wir uns nun diese Klasse in der Shell an:
Wie Sie sehen können, erhalten Sie beim Zugriff auf das
foo
Attribut der Klasse eine ungebundene Methode zurück. Im Klassenspeicher (das Diktat) befindet sich jedoch eine Funktion. Warum ist das? Der Grund dafür ist, dass die Klasse Ihrer Klasse ein implementiert__getattribute__
, das Deskriptoren auflöst. Klingt komplex, ist es aber nicht.C.foo
entspricht in diesem speziellen Fall in etwa diesem Code:Das liegt daran, dass Funktionen eine
__get__
Methode haben, die sie zu Deskriptoren macht. Wenn Sie eine Instanz einer Klasse haben, ist sie fast dieselbe, nur dasNone
ist die Klasseninstanz:Warum macht Python das jetzt? Weil das Methodenobjekt den ersten Parameter einer Funktion an die Instanz der Klasse bindet. Da kommt das Selbst her. Manchmal möchten Sie nicht, dass Ihre Klasse eine Funktion zu einer Methode macht. Hier
staticmethod
kommt das ins Spiel:Der
staticmethod
Dekorateur umschließt Ihre Klasse und implementiert einen Dummy__get__
, der die umschlossene Funktion als Funktion und nicht als Methode zurückgibt:Hoffe das erklärt es.
quelle
staticmethod
Dekorateur wickelt Ihre Klasse (...) Dieser Satz ist ein bisschen wie die Klasse irreführend , die gewickelt wird, die Klasse ist von der Methodefoo
und nicht die Klasse , in derfoo
definiert ist.Wenn Sie ein Klassenmitglied aufrufen, verwendet Python automatisch einen Verweis auf das Objekt als ersten Parameter. Die Variable
self
bedeutet eigentlich nichts, es ist nur eine Codierungskonvention. Sie könnten es nennen,gargaloo
wenn Sie wollten. Der Aufruf vonmethod_two
würde jedoch a auslösenTypeError
, da Python automatisch versucht, einen Parameter (den Verweis auf sein übergeordnetes Objekt) an eine Methode zu übergeben, die als ohne Parameter definiert wurde.Damit es tatsächlich funktioniert, können Sie dies an Ihre Klassendefinition anhängen:
oder Sie könnten den
@staticmethod
Funktionsdekorator verwenden .quelle
quelle
Class.instance_method() # The class cannot use an instance method
es kann verwenden.Class.instance_method(a)
TyeError
Linie an.a.class_method()
, scheint esa.c
aktualisiert worden zu sein1
, also hat der Aufruf vonClass.class_method()
dieClass.c
Variable auf aktualisiert2
.a.c=5
Warum wurde bei der Zuweisung jedochClass.c
nicht auf aktualisiert5
?method_two funktioniert nicht, weil Sie eine Mitgliedsfunktion definieren, aber nicht mitteilen, zu welcher Funktion die Funktion gehört. Wenn Sie die letzte Zeile ausführen, erhalten Sie:
Wenn Sie Elementfunktionen für eine Klasse definieren, muss das erste Argument immer 'self' sein.
quelle
Genaue Erklärung von Armin Ronacher oben, wobei er seine Antworten erweitert, damit Anfänger wie ich es gut verstehen:
Der Unterschied in den in einer Klasse definierten Methoden, ob statische oder Instanzmethode (es gibt noch einen anderen Typ - Klassenmethode - hier nicht besprochen, also überspringen), lag in der Tatsache, ob sie irgendwie an die Klasseninstanz gebunden sind oder nicht. Angenommen, die Methode erhält zur Laufzeit einen Verweis auf die Klasseninstanz
Die
__dict__
Dictionary-Eigenschaft des Klassenobjekts enthält den Verweis auf alle Eigenschaften und Methoden eines Klassenobjekts und damitDie Methode foo ist wie oben beschrieben zugänglich. Ein wichtiger Punkt, der hier zu beachten ist, ist, dass alles in Python ein Objekt ist und daher Verweise im obigen Wörterbuch selbst auf andere Objekte verweisen. Lassen Sie mich sie Class Property Objects nennen - oder als CPO im Rahmen meiner Antwort der Kürze halber.
Wenn ein CPO ein Deskriptor ist, ruft der Python-Interpreter die
__get__()
Methode des CPO auf, um auf den darin enthaltenen Wert zuzugreifen.Um festzustellen, ob ein CPO ein Deskriptor ist, prüft der Python-Interpretor, ob er das Deskriptorprotokoll implementiert. Das Deskriptorprotokoll zu implementieren bedeutet, 3 Methoden zu implementieren
für zB
wo
self
ist der CPO (es kann sich um eine Instanz von list, str, function usw. handeln) und wird von der Laufzeit bereitgestelltinstance
ist die Instanz der Klasse, in der dieser CPO definiert ist (das Objekt 'c' oben) und muss von uns explizit angegeben werdenowner
ist die Klasse, in der dieser CPO definiert ist (das Klassenobjekt 'C' oben) und von uns bereitgestellt werden muss. Dies liegt jedoch daran, dass wir es auf dem CPO aufrufen. Wenn wir es für die Instanz aufrufen, müssen wir dies nicht angeben, da die Laufzeit die Instanz oder ihre Klasse bereitstellen kann (Polymorphismus).value
ist der beabsichtigte Wert für den CPO und muss von uns geliefert werdenNicht alle CPO sind Deskriptoren. Beispielsweise
Dies liegt daran, dass die Listenklasse das Deskriptorprotokoll nicht implementiert.
Daher ist das Argument self in
c.foo(self)
erforderlich, da seine Methodensignatur tatsächlich dies istC.__dict__['foo'].__get__(c, C)
(wie oben erläutert, wird C nicht benötigt, da es herausgefunden oder polymorphisiert werden kann). Aus diesem Grund erhalten Sie auch einen TypeError, wenn Sie das erforderliche Instanzargument nicht übergeben.Wenn Sie feststellen, dass die Methode weiterhin über das Klassenobjekt C referenziert wird und die Bindung mit der Klasseninstanz durch Übergeben eines Kontexts in Form des Instanzobjekts an diese Funktion erreicht wird.
Dies ist ziemlich beeindruckend, denn wenn Sie keinen Kontext oder keine Bindung an die Instanz beibehalten möchten, müssen Sie lediglich eine Klasse schreiben, um den Deskriptor-CPO zu verpacken und seine
__get__()
Methode zu überschreiben, sodass kein Kontext erforderlich ist. Diese neue Klasse wird als Dekorateur bezeichnet und über das Schlüsselwort angewendet@staticmethod
Das Fehlen eines Kontexts im neu verpackten CPO
foo
löst keinen Fehler aus und kann wie folgt überprüft werden:Der Anwendungsfall einer statischen Methode ist eher eine Namespace- und Code-Wartbarkeitsmethode (Herausnehmen aus einer Klasse und Bereitstellen im gesamten Modul usw.).
Es ist möglicherweise besser, statische Methoden als Instanzmethoden zu schreiben, wenn dies möglich ist, es sei denn, Sie müssen die Methoden (wie Zugriffsinstanzvariablen, Klassenvariablen usw.) kontexualisieren. Ein Grund ist, die Speicherbereinigung zu vereinfachen, indem keine unerwünschten Verweise auf Objekte beibehalten werden.
quelle
das ist ein fehler
Zuallererst sollte die erste Zeile so sein (Vorsicht vor Großbuchstaben)
Wenn Sie eine Methode einer Klasse aufrufen, wird sie als erstes Argument (daher der Name self) angezeigt, und method_two gibt diesen Fehler aus
quelle
Das zweite funktioniert nicht, denn wenn Sie es so aufrufen, versucht Python intern, es mit der a_test-Instanz als erstem Argument aufzurufen, aber Ihre method_two akzeptiert keine Argumente, sodass es nicht funktioniert. Sie erhalten eine Laufzeit Error. Wenn Sie das Äquivalent einer statischen Methode wünschen, können Sie eine Klassenmethode verwenden. In Python werden Klassenmethoden viel weniger benötigt als statische Methoden in Sprachen wie Java oder C #. Meistens besteht die beste Lösung darin, eine Methode im Modul außerhalb einer Klassendefinition zu verwenden. Diese arbeiten effizienter als Klassenmethoden.
quelle
Class Test(object): @staticmethod def method_two(): print(“called method_two”)
Ein Anwendungsfall, an den ich gedacht habe, ist, wenn Sie möchten, dass die Funktion Teil einer Klasse ist, der Benutzer jedoch nicht direkt auf die Funktion zugreifen soll. Dasmethod_two
kann also von anderen Funktionen innerhalb derTest
Instanz aufgerufen werden, kann aber nicht mit verwendet werdena_test.method_two()
. Wenn ich verwendedef method_two()
, funktioniert dies für diesen Anwendungsfall? Oder gibt es eine bessere Möglichkeit, die Funktionsdefinition so zu ändern, dass sie für den oben genannten Anwendungsfall wie vorgesehen funktioniert?Der Aufruf von method_two löst eine Ausnahme aus, wenn der self-Parameter nicht akzeptiert wird. Die Python-Laufzeit übergibt ihn automatisch.
Wenn Sie eine statische Methode in einer Python-Klasse erstellen möchten, dekorieren Sie sie mit der
staticmethod decorator
.quelle
Bitte lesen Sie diese Dokumente aus der Guido First Class alles klar erklärt, wie ungebundene, gebundene Methoden geboren werden.
quelle
Die Definition von
method_two
ist ungültig. Wenn Sie anrufenmethod_two
, erhalten SieTypeError: method_two() takes 0 positional arguments but 1 was given
vom Dolmetscher.Eine Instanzmethode ist eine begrenzte Funktion, wenn Sie sie wie aufrufen
a_test.method_two()
. Es akzeptiert automatischself
, was auf eine Instanz von verweistTest
, als ersten Parameter. Über denself
Parameter kann eine Instanzmethode frei auf Attribute zugreifen und diese für dasselbe Objekt ändern.quelle
Ungebundene Methoden
Ungebundene Methoden sind Methoden, die noch nicht an eine bestimmte Klasseninstanz gebunden sind.
Gebundene Methoden
Gebundene Methoden sind diejenigen, die an eine bestimmte Instanz einer Klasse gebunden sind.
Wie hier dokumentiert , kann sich self je nach gebundener, ungebundener oder statischer Funktion auf verschiedene Dinge beziehen.
Schauen Sie sich das folgende Beispiel an:
Da wir die Klasseninstanz nicht verwendet haben -
obj
- beim letzten Aufruf nicht verwendet haben, können wir sagen, dass sie wie eine statische Methode aussieht.Wenn ja, was ist der Unterschied zwischen einem
MyClass.some_method(10)
Aufruf und einem Aufruf einer statischen Funktion, die mit a dekoriert ist?@staticmethod
Dekorateur ?Durch die Verwendung des Dekorators wird ausdrücklich klargestellt, dass die Methode verwendet wird, ohne zuvor eine Instanz dafür zu erstellen. Normalerweise würde man nicht erwarten, dass die Klassenmitgliedsmethoden ohne die Instanz verwendet werden, und der Zugriff darauf kann je nach Struktur der Methode mögliche Fehler verursachen.
Durch Hinzufügen des
@staticmethod
Dekorateurs können wir auch über ein Objekt erreichbar sein.Sie können das obige Beispiel nicht mit den Instanzmethoden ausführen. Sie können den ersten überleben (wie zuvor), aber der zweite wird in einen ungebundenen Aufruf übersetzt,
MyClass.some_method(obj, 10)
der a auslöst,TypeError
da die Instanzmethode ein Argument akzeptiert und Sie unbeabsichtigt versucht haben, zwei zu übergeben.Dann könnten Sie sagen: "Wenn ich statische Methoden sowohl über eine Instanz als auch über eine Klasse aufrufen kann
MyClass.some_static_method
undMyClass().some_static_method
dieselben Methoden verwenden sollte." Ja!quelle
Gebundene Methode = Instanzmethode
Ungebundene Methode = statische Methode.
quelle