Was ist der Unterschied zwischen @staticmethod und @classmethod in Python?
Sie haben vielleicht Python-Code wie diesen Pseudocode gesehen, der die Signaturen der verschiedenen Methodentypen zeigt und eine Dokumentationszeichenfolge zur Erklärung enthält:
class Foo(object):
def a_normal_instance_method(self, arg_1, kwarg_2=None):
'''
Gibt einen Wert zurück, der eine Funktion der Instanz mit ihren Attributen ist
und anderer Argumente wie arg_1 und kwarg2
'''
@staticmethod
def a_static_method(arg_0):
'''
Gibt einen Wert zurück, der eine Funktion von arg_0 ist. Es kennt nicht die
Instanz oder Klasse, von der es aufgerufen wird.
'''
@classmethod
def a_class_method(cls, arg1):
'''
Gibt einen Wert zurück, der eine Funktion der Klasse und anderer Argumente ist.
Achtet auf Vererbung, wird mit der Klasse aufgerufen, von der sie aufgerufen wird.
'''
Die normale Instanzmethode
Zuerst erkläre ich a_normal_instance_method
. Dies wird genau als "Instanzmethode" bezeichnet. Wenn eine Instanzmethode verwendet wird, wird sie als teilweise Funktion verwendet (im Gegensatz zu einer Gesamtfunktion, die für alle Werte definiert ist, wenn sie im Quellcode betrachtet wird). Das heißt, bei Verwendung wird das erste Argument als Instanz des Objekts vordefiniert, mit all seinen angegebenen Attributen. Es hat die Instanz des Objekts daran gebunden und muss von einer Instanz des Objekts aufgerufen werden. Normalerweise greift es auf verschiedene Attribute der Instanz zu.
Zum Beispiel ist dies eine Instanz eines Strings:
', '
Wenn wir die Instanzmethode join
auf diesen String verwenden, um eine andere Iterierbare Liste zu verbinden, ist es offensichtlich eine Funktion der Instanz, zusätzlich zu der Funktion der iterierbaren Liste ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Gebundene Methoden
Instanzmethoden können über einen Punkteinschlag zur späteren Verwendung gebunden werden.
Zum Beispiel bindet dies die Methode str.join
an die Instanz ':'
:
>>> join_with_colons = ':'.join
Und später können wir dies als eine Funktion verwenden, bei der das erste Argument bereits daran gebunden ist. Auf diese Weise funktioniert es wie eine teilweise Funktion an der Instanz:
>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Static Method
Die statische Methode nimmt nicht die Instanz als Argument.
Sie ähnelt sehr einer Funktienebene Module.
Allerdings muss eine Funktienebene-Modulfunktion im Modul leben und speziell an anderen Stellen importiert werden, wo sie verwendet wird.
Wenn sie jedoch an das Objekt angehängt wird, wird es das Objekt bequem durch Importieren und Vererbung folgen.
Ein Beispiel für eine statische Methode ist str.maketrans
, verschoben aus dem string
-Modul in Python 3. Es erstellt eine Übersetzungstabelle, die von str.translate
verwendet werden kann. Es wirkt ziemlich lächerlich, wenn es von einer Instanz eines Strings verwendet wird, wie unten dargestellt, aber das Importieren der Funktion aus dem Modul string
ist eher umständlich, und es ist schön, sie von der Klasse aus aufrufen zu können, wie bei str.maketrans
# demonstrieren Sie die gleiche Funktion, egal ob sie von einer Instanz oder nicht aufgerufen wird:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
In Python 2 müssen Sie diese Funktion aus dem zunehmend weniger nützlichen Modul string
importieren:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Klassenmethode
Eine Klassenmethode ist ähnlich wie eine Instanzmethode darin, dass sie ein implizites erstes Argument annimmt, anstatt jedoch die Instanz zu verwenden, nimmt sie die Klasse an. Oft werden diese als alternative Konstruktoren für eine bessere semantische Verwendung verwendet und unterstützen die Vererbung.
Das kanonischste Beispiel einer integrierten Klassenmethode ist dict.fromkeys
. Sie wird als alternativer Konstruktor von dict verwendet (geeignet, wenn Sie wissen, was Ihre Schlüssel sind und einen Standardwert für sie möchten.)
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Wenn wir von dict erben, können wir denselben Konstruktor verwenden, der eine Instanz der Unterklasse erstellt.
>>> class MyDict(dict): 'Eine Diktionär-Unterklasse, die verwendet wird, um Klassenmethoden zu demonstrieren'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
Sehen Sie sich den Quellcode von Pandas für weitere ähnliche Beispiele von alternativen Konstruktoren an und sehen Sie auch die offizielle Python-Dokumentation zu classmethod
und staticmethod
.
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.