Was ist der Unterschied zwischen einer Methode dekoriert mit @staticmethod
und einer Methode, die mit @classmethod
dekoriert ist?
Aber warum würdest du lieber das eine anstatt das andere verwenden wollen? Was ist ein echtes Anwendungsbeispiel?
Was ist der Unterschied zwischen einer Methode dekoriert mit @staticmethod
und einer Methode, die mit @classmethod
dekoriert ist?
Statische Methoden:
Vorteile von statischen Methoden:
Bequemer zu importieren im Vergleich zu Modul-Ebene Funktionen, da jede Methode nicht speziell importiert werden muss
@staticmethod
def some_static_method(*args, **kwds):
pass
Klassenmethoden:
Diese werden mit der eingebauten Funktion classmethod erstellt.
@classmethod
def some_class_method(cls, *args, **kwds):
pass
@Dekorateure wurden in Python 2.4 hinzugefügt. Wenn Sie Python < 2.4 verwenden, können Sie die Funktion classmethod() und staticmethod() verwenden.
Zum Beispiel, wenn Sie eine Fabrikmethode erstellen möchten (eine Funktion, die je nach Argument eine Instanz einer anderen Implementierung einer Klasse zurückgibt), können Sie etwas wie Folgendes tun:
class Cluster(object):
def _ist_cluster_für(cls, name):
"""
überprüfen, ob diese Klasse der Cluster mit diesem Namen ist
dies ist ein classmethod
"""
return cls.__name__ == name
_ist_cluster_für = classmethod(_ist_cluster_für)
# Statische Methode
def getCluster(name):
"""
statische Fabrikmethode, sollte in der Clusterklasse sein
gibt ein Clusterobjekt für den angegebenen Namen zurück
"""
for cls in Cluster.__subclasses__():
if cls._ist_cluster_für(name):
return cls()
getCluster = staticmethod(getCluster)
Beachten Sie auch, dass dies ein gutes Beispiel für die Verwendung einer classmethod und einer statischen Methode ist. Die statische Methode gehört eindeutig zur Klasse, da sie die Klasse Cluster intern verwendet. Die classmethod benötigt nur Informationen über die Klasse und keine Instanz des Objekts.
Ein weiterer Vorteil, die Methode _ist_cluster_für
zu einer classmethod zu machen, besteht darin, dass eine Unterklasse entscheiden kann, ihre Implementierung zu ändern, möglicherweise, weil sie ziemlich allgemein ist und mehr als einen Typ von Cluster handhaben kann, sodass nur die Überprüfung des Klassennamens nicht ausreichen würde.
Lassen Sie mich zuerst die Ähnlichkeit zwischen einer Methode erklären, die mit @classmethod gegenüber @staticmethod dekoriert ist.
Ähnlichkeit: Beide können direkt auf die Klasse selbst aufgerufen werden, und nicht nur auf die Instanz der Klasse. Also sind beide gewissermaßen Klassenmethoden.
Unterschied: Eine Klassenmethode erhält die Klasse selbst als ersten Argument, während eine statische Methode dies nicht tut.
Also ist eine statische Methode gewissermaßen nicht an die Klasse selbst gebunden und hängt einfach dort herum, nur weil sie eine damit verbundene Funktionalität haben könnte.
>>> class Klaus:
@classmethod
def classmthd(*args):
return args
@staticmethod
def staticmthd(*args):
return args
# 1. classmethod ohne Argument aufrufen
>>> Klaus.classmthd()
(__main__.Klaus,) # die Klasse wird als erstes Argument übergeben
# 2. classmethod mit 1 Argument aufrufen
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')
# 3. statische Methode ohne Argument aufrufen
>>> Klaus.staticmthd()
()
# 4. statische Methode mit 1 Argument aufrufen
>>> Klaus.staticmthd('chumma')
('chumma',)
@staticmethod
deaktiviert lediglich die Standardfunktion als Methodenbeschreibung. classmethod
wickelt Ihre Funktion in einen aufrufbaren Container ein, der eine Referenz auf die eigene Klasse als ersten Argument übergibt:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
>>> classmethod(f).__get__(None, C)
>
Tatsächlich hat classmethod
einen Laufzeitoverhead, ermöglicht jedoch den Zugriff auf die eigene Klasse. Alternativ empfehle ich die Verwendung einer Metaklasse und das Platzieren der Klassenmethoden auf dieser Metaklasse:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
Ein möglicher Nachteil einer Metaklasse für mich ist, dass Sie die Klassenmethode nicht direkt auf einer Instanz aufrufen können. c = C(); c.foo()
wirft einen AttributeError, stattdessen müssten Sie type(c).foo()
verwenden. Dies könnte auch als ein Feature betrachtet werden - ich kann jedoch keinen Grund dafür nennen.
Der definitive Leitfaden zur Verwendung von statischen, Klassen- oder abstrakten Methoden in Python ist ein guter Link zu diesem Thema und fasst es wie folgt zusammen.
@staticmethod
Funktion ist nichts anderes als eine Funktion, die innerhalb einer Klasse definiert ist. Sie kann aufgerufen werden, ohne zuerst die Klasse zu instanziieren. Ihre Definition ist unveränderlich durch Vererbung.
@classmethod
Funktion kann auch ohne Instanziierung der Klasse aufgerufen werden, aber ihre Definition folgt der Unterklasse, nicht der Elternklasse, durch Vererbung, kann von der Unterklasse überschrieben werden. Das liegt daran, dass das erste Argument für die @classmethod
Funktion immer cls (Klasse) sein muss.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
27 Stimmen
Statische Methoden sind manchmal als Funktionen auf Modulniveau in Python besser aufgehoben für die Sauberkeit. Mit einer Modulfunktion ist es einfacher, nur die Funktion zu importieren, die Sie benötigen und unnötige "."-Syntax zu vermeiden (ich sehe dich an, Objective-C). Klassenmethoden haben mehr Verwendung, da sie in Kombination mit Polymorphismus verwendet werden können, um Funktionen im "Factory Pattern" zu erstellen. Dies liegt daran, dass Klassenmethoden die Klasse als impliziten Parameter erhalten.
64 Stimmen
Tl;dr >> Im Vergleich zu normalen Methoden können statische Methoden und Klassenmethoden auch über die Klasse aufgerufen werden, aber im Gegensatz zu Klassenmethoden sind statische Methoden vererbungsfest.
9 Stimmen
Ähnlicher Vortrag von Raymond Hettinger zum Thema: youtube.com/watch?v=HTLu2DFOdTg
2 Stimmen
More precise youtube.com/watch?v=HTLu2DFOdTg&feature=youtu.be&t=2689 Sie benötigen nur Klassenmethode für alternative Konstruktoren. Andernfalls können Sie staticmethod verwenden und auf jedes Klassenattribut (über. / Dot) mit dem etwas informativeren tatsächlichen "Klassenname" anstelle von cls wie in classmethod zugreifen.