Was ist der Unterschied zwischen einer mit @staticmethod
und einer dekorierten Funktion @classmethod
?
python
oop
methods
python-decorators
Daryl Spitzer
quelle
quelle
Antworten:
Vielleicht ein bisschen von Beispielcode helfen: Beachten Sie den Unterschied in der Anruf Unterschriften
foo
,class_foo
undstatic_foo
:Im Folgenden wird die übliche Art und Weise beschrieben, wie eine Objektinstanz eine Methode aufruft. Die Objektinstanz
a
wird implizit als erstes Argument übergeben.Bei Klassenmethoden wird die Klasse der Objektinstanz implizit als erstes Argument anstelle von übergeben
self
.Sie können auch
class_foo
mit der Klasse aufrufen . Wenn Sie etwas als Klassenmethode definieren, liegt dies wahrscheinlich daran, dass Sie es eher von der Klasse als von einer Klasseninstanz aus aufrufen möchten.A.foo(1)
hätte einen TypeError ausgelöst,A.class_foo(1)
funktioniert aber einwandfrei :Eine Verwendung, die Menschen für Klassenmethoden gefunden haben, besteht darin, vererbbare alternative Konstruktoren zu erstellen .
Bei staticmethods werden weder
self
(die Objektinstanz) nochcls
(die Klasse) implizit als erstes Argument übergeben. Sie verhalten sich wie einfache Funktionen, außer dass Sie sie von einer Instanz oder der Klasse aus aufrufen können:Statische Methoden werden verwendet, um Funktionen zu gruppieren, die eine logische Verbindung mit einer Klasse zur Klasse haben.
foo
ist nur eine Funktion, aber wenn Sie aufrufen, erhaltena.foo
Sie nicht nur die Funktion, sondern eine "teilweise angewendete" Version der Funktion, wobei die Objektinstanza
als erstes Argument an die Funktion gebunden ist.foo
erwartet 2 Argumente, währenda.foo
nur 1 Argument erwartet wird.a
ist gebunden anfoo
. Das ist es, was mit dem Begriff "gebunden" unten gemeint ist:Mit
a.class_foo
,a
nicht gebundenclass_foo
, sondern die KlasseA
gebunden ist , zuclass_foo
.Hier gibt eine statische Methode, obwohl es sich um eine Methode handelt,
a.static_foo
nur eine gute alte Funktion ohne gebundene Argumente zurück.static_foo
erwartet 1 Argument unda.static_foo
erwartet auch 1 Argument.Und natürlich passiert dasselbe, wenn Sie stattdessen
static_foo
mit der Klasse anrufenA
.quelle
@staticmethod
könnte es helfen, Ihren Code zu organisieren, indem er von Unterklassen überschrieben wird. Ohne sie würden Varianten der Funktion im Modul-Namespace herumschweben.@staticmethod
- Sie können damit Cruft entfernen. Ich implementiere eine Programmiersprache in Python - bibliotheksdefinierte Funktionen verwenden eine statischeexecute
Methode, bei der benutzerdefinierte Funktionen Instanzargumente erfordern (dh den Funktionskörper). Dieser Dekorator eliminiert Warnungen vor "nicht verwendeten Parametern selbst" im PyCharm-Inspektor.Eine statische Methode ist eine Methode, die nichts über die Klasse oder Instanz weiß, für die sie aufgerufen wurde. Es werden nur die Argumente abgerufen, die übergeben wurden, kein implizites erstes Argument. In Python ist es grundsätzlich nutzlos - Sie können einfach eine Modulfunktion anstelle einer statischen Methode verwenden.
Eine Klassenmethode hingegen ist eine Methode, die die Klasse, für die sie aufgerufen wurde, oder die Klasse der Instanz, für die sie aufgerufen wurde, als erstes Argument übergibt. Dies ist nützlich, wenn die Methode eine Factory für die Klasse sein soll: Da sie die tatsächliche Klasse erhält, für die sie als erstes Argument aufgerufen wurde, können Sie immer die richtige Klasse instanziieren, auch wenn Unterklassen beteiligt sind. Beobachten Sie beispielsweise, wie
dict.fromkeys()
eine Klassenmethode eine Instanz der Unterklasse zurückgibt, wenn sie für eine Unterklasse aufgerufen wird:quelle
Grundsätzlich
@classmethod
hat eine Methode, deren erstes Argument die Klasse ist, von der sie aufgerufen wird (und nicht die Klasseninstanz),@staticmethod
keine impliziten Argumente.quelle
Offizielle Python-Dokumente:
@classmethod
@staticmethod
quelle
Hier ist ein kurzer Artikel zu dieser Frage
quelle
Um zu entscheiden, ob Sie @staticmethod oder @classmethod verwenden möchten, müssen Sie sich Ihre Methode ansehen. Wenn Ihre Methode auf andere Variablen / Methoden in Ihrer Klasse zugreift, verwenden Sie @classmethod . Wenn Ihre Methode jedoch keine anderen Teile der Klasse berührt, verwenden Sie @staticmethod.
quelle
cls._counter
wäre auch danncls._counter
noch, wenn der Code in eine andere Klasse gestellt wird oder der Klassenname geändert wird.Apple._counter
ist spezifisch für dieApple
Klasse; Für eine andere Klasse oder wenn der Klassenname geändert wird, müssten Sie die referenzierte Klasse ändern.Möglicherweise haben Sie Python-Code wie diesen Pseudocode gesehen, der die Signaturen der verschiedenen Methodentypen demonstriert und eine Dokumentzeichenfolge zur Erläuterung der einzelnen Methoden bereitstellt:
Die normale Instanzmethode
Zuerst werde ich erklären
a_normal_instance_method
. Dies wird genau als " Instanzmethode " bezeichnet " bezeichnet. Wenn eine Instanzmethode verwendet wird, wird sie als Teilfunktion verwendet (im Gegensatz zu einer Gesamtfunktion, die für alle Werte definiert ist, wenn sie im Quellcode angezeigt wird). Bei Verwendung wird das erste der Argumente als Instanz der vordefiniert Objekt mit all seinen gegebenen Attributen. Es ist an die Instanz des Objekts gebunden und muss von einer Instanz des Objekts aufgerufen werden. In der Regel wird auf verschiedene Attribute der Instanz zugegriffen.Dies ist beispielsweise eine Instanz einer Zeichenfolge:
Wenn wir die Instanzmethode
join
für diese Zeichenfolge verwenden, um eine andere iterable zu verbinden, ist dies ganz offensichtlich eine Funktion der Instanz und zusätzlich eine Funktion der iterierbaren Liste['a', 'b', 'c']
:Gebundene Methoden
Instanzmethoden können zur späteren Verwendung über eine gepunktete Suche gebunden werden.
Dies bindet die
str.join
Methode beispielsweise an die':'
Instanz:Und später können wir dies als eine Funktion verwenden, an die bereits das erste Argument gebunden ist. Auf diese Weise funktioniert es wie eine Teilfunktion für die Instanz:
Statische Methode
Die statische Methode funktioniert nicht nehmen Sie die Instanz als Argument.
Es ist einer Funktion auf Modulebene sehr ähnlich.
Eine Funktion auf Modulebene muss sich jedoch im Modul befinden und speziell an andere Orte importiert werden, an denen sie verwendet wird.
Wenn es jedoch an das Objekt angehängt ist, folgt es dem Objekt bequem durch Importieren und Vererbung.
Ein Beispiel für eine statische Methode ist
str.maketrans
, aus dem verschobenstring
Verschieben Modul in Python 3. Dadurch wird eine Übersetzungstabelle für den Verbrauch durch geeignetstr.translate
. Es scheint ziemlich albern zu sein, wenn es von einer Instanz eines Strings verwendet wird, wie unten gezeigt, aber das Importieren der Funktion aus demstring
Modul ist ziemlich umständlich, und es ist schön, sie aus der Klasse aufrufen zu können, wie instr.maketrans
In Python 2 müssen Sie diese Funktion aus dem zunehmend weniger nützlichen String-Modul importieren:
Klassenmethode
Eine Klassenmethode ähnelt einer Instanzmethode darin, dass sie ein implizites erstes Argument verwendet, aber anstatt die Instanz zu verwenden, wird die Klasse verwendet. Häufig werden diese als alternative Konstruktoren für eine bessere semantische Verwendung verwendet und unterstützen die Vererbung.
Das kanonischste Beispiel für eine eingebaute Klassenmethode ist
dict.fromkeys
. Es wird als alternativer Konstruktor von dict verwendet (gut geeignet, wenn Sie wissen, was Ihre Schlüssel sind und einen Standardwert für sie wünschen).Wenn wir diktieren, können wir denselben Konstruktor verwenden, der eine Instanz der Unterklasse erstellt.
Weitere ähnliche Beispiele für alternative Konstruktoren finden Sie im Pandas-Quellcode sowie in der offiziellen Python-Dokumentation zu
classmethod
undstaticmethod
.quelle
Ich fing an, Programmiersprache mit C ++ und dann Java und dann Python zu lernen, und so störte mich diese Frage auch sehr, bis ich die einfache Verwendung von jedem verstand.
Klassenmethode: Python hat im Gegensatz zu Java und C ++ keine Konstruktorüberladung. Und um dies zu erreichen, könnten Sie verwenden
classmethod
. Das folgende Beispiel erklärt diesNehmen wir an, wir haben eine
Person
Klasse, die zwei Argumente akzeptiertfirst_name
undlast_name
die Instanz von erstelltPerson
.Wenn die Anforderung kommt, dass Sie eine Klasse nur mit einem einzigen Namen erstellen müssen
first_name
, können Sie in Python so etwas nicht tun.Dies gibt Ihnen eine Fehlermeldung, wenn Sie versuchen, ein Objekt (eine Instanz) zu erstellen.
Sie können jedoch dasselbe erreichen,
@classmethod
wie unten erwähntStatische Methode: Dies ist ziemlich einfach, es ist nicht an eine Instanz oder Klasse gebunden, und Sie können dies einfach mit dem Klassennamen aufrufen.
Nehmen wir also an, Sie benötigen im obigen Beispiel eine Validierung,
first_name
die 20 Zeichen nicht überschreiten sollte. Sie können dies einfach tun.und Sie könnten einfach mit anrufen
class name
quelle
def __init__(self, first_name, last_name="")
anstelle der Klassenmethode verwendetget_person
. Auch das Ergebnis ist in diesem Fall genau das gleiche.Ich denke, eine bessere Frage ist "Wann würden Sie @classmethod vs @staticmethod verwenden?"
Mit @classmethod können Sie problemlos auf private Mitglieder zugreifen, die der Klassendefinition zugeordnet sind. Dies ist eine großartige Möglichkeit, Singletons oder Factory-Klassen zu erstellen, die die Anzahl der vorhandenen Instanzen der erstellten Objekte steuern.
@staticmethod bietet marginale Leistungssteigerungen, aber ich habe noch keine produktive Verwendung einer statischen Methode innerhalb einer Klasse gesehen, die als eigenständige Funktion außerhalb der Klasse nicht erreicht werden konnte.
quelle
@decorators wurden in Python 2.4 hinzugefügt. Wenn Sie Python <2.4 verwenden, können Sie die Funktionen classmethod () und staticmethod () verwenden.
Wenn Sie beispielsweise eine Factory-Methode erstellen möchten (eine Funktion, die eine Instanz einer anderen Implementierung einer Klasse zurückgibt, je nachdem, welches Argument sie erhält), können Sie Folgendes tun:
Beachten Sie auch, dass dies ein gutes Beispiel für die Verwendung einer Klassenmethode und einer statischen Methode ist. Die statische Methode gehört eindeutig zur Klasse, da sie den Klassencluster intern verwendet. Die Klassenmethode benötigt nur Informationen über die Klasse und keine Instanz des Objekts.
Ein weiterer Vorteil,
_is_cluster_for
wenn Sie die Methode zu einer Klassenmethode machen, besteht darin, dass eine Unterklasse entscheiden kann, ihre Implementierung zu ändern, möglicherweise weil sie ziemlich allgemein gehalten ist und mehr als einen Clustertyp verarbeiten kann. Daher reicht es nicht aus, nur den Namen der Klasse zu überprüfen.quelle
Statische Methoden:
Vorteile statischer Methoden:
Der Import ist im Vergleich zu Funktionen auf Modulebene bequemer, da nicht jede Methode speziell importiert werden muss
Klassenmethoden:
Diese werden mit der in classmethod integrierten Funktion erstellt.
quelle
@staticmethod
Deaktiviert einfach die Standardfunktion als Methodendeskriptor. classmethod umschließt Ihre Funktion mit einem aufrufbaren Container, der als erstes Argument einen Verweis auf die besitzende Klasse übergibt:Hat zwar
classmethod
einen Laufzeit-Overhead, ermöglicht aber den Zugriff auf die besitzende Klasse. Alternativ empfehle ich, eine Metaklasse zu verwenden und die Klassenmethoden auf diese Metaklasse anzuwenden:quelle
c = C(); c.foo()
löst AttributeError aus, das müssten Sie tuntype(c).foo()
. Dies könnte auch als eine Funktion angesehen werden - ich kann mir nicht vorstellen, warum Sie das möchten.Die endgültige Anleitung zur Verwendung statischer, klassenbezogener oder abstrakter Methoden in Python ist ein guter Link für dieses Thema und fasst es wie folgt zusammen.
@staticmethod
Funktion ist nichts anderes als eine innerhalb einer Klasse definierte Funktion. Es kann aufgerufen werden, ohne zuerst die Klasse zu instanziieren. Die Definition ist über die Vererbung unveränderlich.@classmethod
Die Funktion kann auch aufgerufen werden, ohne die Klasse zu instanziieren. Ihre Definition folgt jedoch der Unterklasse. Die übergeordnete Klasse kann über die Vererbung von der Unterklasse überschrieben werden. Das liegt daran, dass das erste Argument für die@classmethod
Funktion immer cls (Klasse) sein muss.quelle
Nur das erste Argument unterscheidet sich :
Ausführlicher...
normale Methode
Wenn die Methode eines Objekts aufgerufen wird, erhält es automatisch ein zusätzliches Argument
self
als erstes Argument. Das heißt, Methodemuss mit 2 Argumenten aufgerufen werden.
self
wird automatisch übergeben und ist das Objekt selbst .Klassenmethode
Wenn die Methode dekoriert ist
Das automatisch bereitgestellte Argument ist nicht
self
, sondern die Klasse vonself
.statische Methode
Wenn die Methode dekoriert ist
Die Methode erhält überhaupt kein automatisches Argument. Es werden nur die Parameter angegeben, mit denen es aufgerufen wird.
Verwendungen
classmethod
wird hauptsächlich für alternative Konstruktoren verwendet.staticmethod
verwendet nicht den Status des Objekts. Es könnte eine Funktion außerhalb einer Klasse sein. Es wird nur in die Klasse eingefügt, um Funktionen mit ähnlichen Funktionen zu gruppieren (z. B. dieMath
statischen Methoden der Java- Klasse).quelle
Lassen Sie mich zunächst die Ähnlichkeit zwischen einer mit @classmethod dekorierten Methode und @staticmethod erläutern.
Ähnlichkeit: Beide können für die Klasse selbst aufgerufen werden und nicht nur für die Instanz der Klasse. In gewisser Weise sind beide Methoden von Class .
Unterschied: Eine Klassenmethode empfängt die Klasse selbst als erstes Argument, eine statische Methode nicht.
Eine statische Methode ist also gewissermaßen nicht an die Klasse selbst gebunden und hängt nur daran, nur weil sie möglicherweise eine verwandte Funktionalität hat.
quelle
Eine weitere Überlegung in Bezug auf die statische Methode im Vergleich zur Klassenmethode betrifft die Vererbung. Angenommen, Sie haben die folgende Klasse:
Und dann möchten Sie
bar()
in einer untergeordneten Klasse überschreiben :Dies funktioniert, aber beachten Sie, dass die
bar()
Implementierung in der untergeordneten Klasse (Foo2
) jetzt nichts Spezifisches mehr für diese Klasse nutzen kann. Zum Beispiel, sagen wirFoo2
hatten eine Methode aufgerufen ,magic()
die Sie im verwenden möchtenFoo2
Umsetzungbar()
:Die Abhilfe wäre hier zu nennen
Foo2.magic()
inbar()
, aber dann selbst Sie zu wiederholen (wenn der NameFoo2
ändert, werden Sie dürfen nicht vergessen, dass aktualisierenbar()
Methode).Für mich ist dies eine leichte Verletzung des Open / Closed-Prinzips , da eine getroffene Entscheidung
Foo
Ihre Fähigkeit beeinträchtigt, allgemeinen Code in einer abgeleiteten Klasse umzugestalten (dh weniger offen für Erweiterungen). Wennbar()
ein warenclassmethod
würden wir in Ordnung sein:Gibt:
In Foo2 MAGIC
quelle
Ich werde versuchen, den grundlegenden Unterschied anhand eines Beispiels zu erklären.
1 - Wir können statische und Klassenmethoden direkt aufrufen, ohne sie zu initialisieren
2- Die statische Methode kann keine Selbstmethode aufrufen, kann jedoch andere statische Methoden und Klassenmethoden aufrufen
3- Statische Methoden gehören zur Klasse und verwenden überhaupt kein Objekt.
4- Die Klassenmethode ist nicht an ein Objekt gebunden, sondern an eine Klasse.
quelle
@classmethod: kann verwendet werden, um einen gemeinsamen globalen Zugriff auf alle Instanzen dieser Klasse zu erstellen ..... wie das Aktualisieren eines Datensatzes durch mehrere Benutzer .... Ich fand insbesondere, dass es auch beim Erstellen von Singletons voll ist ..: )
@static-Methode: hat nichts mit der Klasse oder Instanz zu tun, die mit ... verknüpft ist. Zur besseren Lesbarkeit kann jedoch eine statische Methode verwendet werden
quelle
Vielleicht möchten Sie den Unterschied berücksichtigen zwischen:
und
Dies hat sich zwischen Python2 und Python3 geändert:
python2:
python3:
Also mit
@staticmethod
for-Methoden, die nur direkt von der Klasse aufgerufen werden, ist in python3 optional geworden. Wenn Sie sie sowohl aus der Klasse als auch aus der Instanz aufrufen möchten, müssen Sie weiterhin den@staticmethod
Dekorator verwenden.Die anderen Fälle wurden durch die Antwort von unutbus gut abgedeckt.
quelle
Eine Klassenmethode empfängt die Klasse als implizites erstes Argument, genau wie eine Instanzmethode die Instanz empfängt. Es ist eine Methode, die an die Klasse und nicht an das Objekt der Klasse gebunden ist. Sie hat Zugriff auf den Status der Klasse, da ein Klassenparameter verwendet wird, der auf die Klasse und nicht auf die Objektinstanz verweist. Es kann einen Klassenstatus ändern, der für alle Instanzen der Klasse gilt. Beispielsweise kann eine Klassenvariable geändert werden, die auf alle Instanzen anwendbar ist.
Andererseits erhält eine statische Methode im Vergleich zu Klassenmethoden oder Instanzmethoden kein implizites erstes Argument. Und kann nicht auf den Klassenstatus zugreifen oder diesen ändern. Es gehört nur zur Klasse, weil dies aus gestalterischer Sicht der richtige Weg ist. Die Funktionalität ist jedoch zur Laufzeit nicht an die Klasse gebunden.
Verwenden Sie als Richtlinie statische Methoden als Dienstprogramme und Klassenmethoden beispielsweise als Factory. Oder vielleicht um einen Singleton zu definieren. Verwenden Sie Instanzmethoden, um den Status und das Verhalten von Instanzen zu modellieren.
Hoffe ich war klar!
quelle
Mein Beitrag zeigt den Unterschied zwischen
@classmethod
,@staticmethod
und Instanzmethoden, einschließlich der Frage, wie eine Instanz indirekt a aufrufen kann@staticmethod
. Aber anstatt indirekt ein@staticmethod
von einer Instanz aufzurufen , kann es "pythonischer" sein, es privat zu machen. Etwas von einer privaten Methode zu bekommen, wird hier nicht demonstriert, aber es ist im Grunde das gleiche Konzept.quelle
Klassenmethoden werden, wie der Name schon sagt, verwendet, um Änderungen an Klassen und nicht an den Objekten vorzunehmen. Um Änderungen an Klassen vorzunehmen, ändern sie die Klassenattribute (nicht die Objektattribute), da Sie auf diese Weise Klassen aktualisieren. Dies ist der Grund, warum Klassenmethoden die Klasse (üblicherweise mit 'cls' bezeichnet) als erstes Argument verwenden.
Statische Methoden hingegen werden verwendet, um Funktionen auszuführen, die nicht an die Klasse gebunden sind, dh keine Klassenvariablen lesen oder schreiben. Daher nehmen statische Methoden keine Klassen als Argumente an. Sie werden verwendet, damit Klassen Funktionen ausführen können, die nicht direkt mit dem Zweck der Klasse zusammenhängen.
quelle
Analysieren Sie @staticmethod buchstäblich liefern verschiedene Erkenntnisse.
Eine normale Methode einer Klasse ist eine implizite dynamische Methode, die die Instanz als erstes Argument verwendet.
Im Gegensatz dazu nimmt eine statische Methode die Instanz nicht als erstes Argument und wird daher als "statisch" bezeichnet .
Eine statische Methode ist in der Tat eine solche normale Funktion wie die außerhalb einer Klassendefinition.
Es ist zum Glück in der Klasse zusammengefasst, nur um näher an der Stelle zu stehen, an der es angewendet wird, oder Sie können herumblättern, um es zu finden.
quelle
Ich denke, eine rein Python-Version von
staticmethod
und zu gebenclassmethod
würde helfen, den Unterschied zwischen ihnen auf Sprachebene zu verstehen.Beide sind Nicht-Daten-Deskriptoren (es wäre einfacher, sie zu verstehen, wenn Sie zuerst mit Deskriptoren vertraut sind ).
quelle
staticmethod hat keinen Zugriff auf Attribute des Objekts, der Klasse oder der übergeordneten Klassen in der Vererbungshierarchie. Es kann direkt in der Klasse aufgerufen werden (ohne ein Objekt zu erstellen).
Klassenmethode hat keinen Zugriff auf Attribute des Objekts. Es kann jedoch auf Attribute der Klasse und der übergeordneten Klassen in der Vererbungshierarchie zugreifen. Es kann direkt in der Klasse aufgerufen werden (ohne ein Objekt zu erstellen). Wenn es für das Objekt aufgerufen wird, ist es dasselbe wie die normale Methode, die nicht
self.<attribute(s)>
zugreift und darauf zugreiftself.__class__.<attribute(s)>
nur darauf .Denken Sie, wir haben eine Klasse mit
b=2
, wir werden ein Objekt erstellen und dieses daraufb=4
zurücksetzen. Staticmethod kann nicht auf nichts von vorherigen zugreifen. Classmethod kann.b==2
nur über zugreifencls.b
. Die normale Methode kann auf beide zugreifen:.b==4
überself.b
und.b==2
überself.__class__.b
.Wir könnten dem KISS-Stil folgen (halten Sie es einfach, dumm): Verwenden Sie keine statischen Methoden und Klassenmethoden, verwenden Sie keine Klassen, ohne sie zu instanziieren, greifen Sie nur auf die Attribute des Objekts zu
self.attribute(s)
. Es gibt Sprachen, in denen das OOP auf diese Weise implementiert wird, und ich denke, es ist keine schlechte Idee. :) :)quelle
Ein schneller Überblick über andere identische Methoden in iPython zeigt, dass
@staticmethod
geringfügige Leistungssteigerungen (in Nanosekunden) erzielt werden, ansonsten scheint dies jedoch keine Funktion zu erfüllen . Außerdem werden Leistungssteigerungen wahrscheinlich durch die zusätzliche Verarbeitung der Methodestaticmethod()
während der Kompilierung (die vor jeder Codeausführung beim Ausführen eines Skripts erfolgt) zunichte gemacht.Aus Gründen der Lesbarkeit des Codes würde ich es vermeiden, es
@staticmethod
sei denn, Ihre Methode wird für viele Arbeiten verwendet, bei denen die Nanosekunden zählen.quelle