Was ist der Unterschied zwischen einer mit dekorierten Funktion? @staticmethod
und eines mit dekoriert @classmethod
?
Was ist der Unterschied zwischen einer mit dekorierten Funktion? @staticmethod
und eines mit dekoriert @classmethod
?
Vielleicht hilft ein bisschen Beispielcode: Beachten Sie den Unterschied in den Rufsignaturen von foo
, class_foo
und static_foo
:
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
a=A()
Im Folgenden ist der übliche Weg beschrieben, wie eine Objektinstanz eine Methode aufruft. Die Objektinstanz, a
, wird implizit als erstes Argument übergeben.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
Mit Klassenmethodenwird die Klasse der Objektinstanz implizit als erstes Argument übergeben self
.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Sie können auch anrufen class_foo
Verwenden der Klasse. In der Tat, wenn Sie etwas definieren zu sein
Eine Klassenmethode ist wahrscheinlich, weil Sie beabsichtigen, sie von der Klasse und nicht von einer Klasseninstanz aus aufzurufen. A.foo(1)
hätte einen TypeError ausgelöst, aber A.class_foo(1)
funktioniert gut:
A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Eine Verwendung, die Leute für Klassenmethoden gefunden haben, ist zu erstellen vererbbare alternative Konstruktoren.
Mit statischen Methoden, weder self
(die Objektinstanz) noch cls
(Die Klasse) wird implizit als erstes Argument übergeben. Sie verhalten sich wie normale Funktionen, außer dass Sie sie von einer Instanz oder der Klasse aus aufrufen können:
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
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 anrufen a.foo
Du bekommst nicht nur die Funktion,
Sie erhalten eine "teilweise angewendete" Version der Funktion mit der Objektinstanz a
gebunden als erstes Argument an die Funktion. foo
erwartet 2 Argumente, während a.foo
erwartet nur 1 Argument.
a
ist gebunden an foo
. Das ist mit dem Begriff "gebunden" gemeint:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
Mit a.class_foo
, a
ist nicht verpflichtet class_foo
eher die Klasse A
ist gebunden an class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Hier, mit einer statischen Methode, obwohl es eine Methode ist, a.static_foo
kommt einfach zurück
eine gute Ole-Funktion ohne gebundene Argumente. static_foo
erwartet 1 Argument und
a.static_foo
erwartet 1 Argument auch.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
Und natürlich passiert das Gleiche, wenn Sie anrufen static_foo
mit der Klasse A
stattdessen.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
EIN statische Methode ist eine Methode, die nichts über die Klasse oder Instanz weiß, an der sie aufgerufen wurde. Es erhält nur die Argumente, die übergeben wurden, kein implizites erstes Argument. In Python ist es praktisch nutzlos - Sie können einfach eine Modulfunktion anstelle einer statischen Methode verwenden.
EIN KlassenmethodeAuf der anderen Seite ist eine Methode, die die Klasse, an der sie aufgerufen wurde, oder die Klasse der Instanz, an der sie aufgerufen wurde, als erstes Argument übergeben wird. Dies ist nützlich, wenn Sie möchten, dass die Methode eine Factory für die Klasse ist: Da sie die tatsächliche Klasse als erstes Argument aufruft, können Sie immer die richtige Klasse instanziieren, selbst wenn Unterklassen beteiligt sind. Beobachte zum Beispiel wie dict.fromkeys()
, eine Klassenmethode, gibt eine Instanz der Unterklasse zurück, wenn sie für eine Unterklasse aufgerufen wird:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
Grundsätzlich gilt @classmethod
macht eine Methode, deren erstes Argument die Klasse ist, von der sie aufgerufen wird (und nicht die Klasseninstanz), @staticmethod
hat keine impliziten Argumente.
Offizielle Python-Dokumente:
Eine Klassenmethode erhält die Klasse als implizites erstes Argument, genau wie ein Instanzmethode empfängt die Instanz. Verwenden Sie dies, um eine Klassenmethode zu deklarieren Idiom:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
Das
@classmethod
Form ist eine Funktion Dekorateur - siehe Beschreibung von Funktionsdefinitionen in Funktion Definitionen für Details.Es kann entweder in der Klasse aufgerufen werden (sowie
C.f()
) oder auf einer Instanz (sowieC().f()
). Die Instanz ist außer für seine Klasse ignoriert. Wenn ein Klassenmethode wird für eine Ableitung aufgerufen Klasse, das abgeleitete Klassenobjekt ist als das implizierte erste Argument übergeben.Klassenmethoden unterscheiden sich von C ++ oder statische Java-Methoden. wenn du willst diese, seht ihr?
staticmethod()
in diesem Sektion.
Eine statische Methode erhält keine implizites erstes Argument. Um a zu deklarieren statische Methode, verwende dieses Idiom:
class C: @staticmethod def f(arg1, arg2, ...): ...
Das
@staticmethod
Form ist eine Funktion Dekorateur - siehe Beschreibung von Funktionsdefinitionen in Funktion Definitionen für Details.Es kann entweder in der Klasse aufgerufen werden (sowie
C.f()
) oder auf einer Instanz (sowieC().f()
). Die Instanz ist außer für seine Klasse ignoriert.Die statischen Methoden in Python sind ähnlich zu denen in Java oder C ++ gefunden. Für ein fortgeschrittenes Konzept, siehe
classmethod()
in diesem Abschnitt.
Hier ist ein kurzer Artikel zu dieser Frage
@staticmethod-Funktion ist nichts anderes als eine Funktion, die in einer Klasse definiert ist. Es kann aufgerufen werden, ohne zuerst die Klasse zu instanziieren. Die Definition ist durch Vererbung unveränderbar.
@classmethod-Funktion kann auch aufgerufen werden, ohne die Klasse zu instanziieren, aber ihre Definition folgt der Sub-Klasse und nicht der Parent-Klasse über die Vererbung. Das liegt daran, dass das erste Argument für die Funktion @classmethod immer cls (class) sein muss.
Um zu entscheiden, ob zu verwenden @StaticMethode oder @ Klassenmethode Sie müssen in Ihre Methode schauen. Wenn Ihre Methode auf andere Variablen / Methoden in Ihrer Klasse zugreift, verwenden Sie @classmethod. Auf der anderen Seite, wenn Ihre Methode keine anderen Teile der Klasse berührt, dann verwenden Sie @staticmethod.
class Apple:
_counter = 0
@staticmethod
def about_apple():
print('Apple is good for you.')
# note you can still access other member of the class
# but you have to use the class instance
# which is not very nice, because you have repeat yourself
#
# For example:
# @staticmethod
# print('Number of apples have been juiced: %s' % Apple._counter)
#
# @classmethod
# print('Number of apples have been juiced: %s' % cls._counter)
#
# @classmethod is especially useful when you move your function to other class,
# you don't have to rename the class reference
@classmethod
def make_apple_juice(cls, number_of_apples):
print('Make juice:')
for i in range(number_of_apples):
cls._juice_this(i)
@classmethod
def _juice_this(cls, apple):
print('Juicing %d...' % apple)
cls._counter += 1
Was ist der Unterschied zwischen @staticmethod und @classmethod in Python?
Möglicherweise haben Sie Python-Code wie diesen Pseudocode gesehen, der die Signaturen der verschiedenen Methodentypen demonstriert und einen Docstring bereitstellt, um jedes zu erklären:
class Foo(object):
def a_normal_instance_method(self, arg_1, kwarg_2=None):
'''
Return a value that is a function of the instance with its
attributes, and other arguments such as arg_1 and kwarg2
'''
@staticmethod
def a_static_method(arg_0):
'''
Return a value that is a function of arg_0. It does not know the
instance or class it is called from.
'''
@classmethod
def a_class_method(cls, arg1):
'''
Return a value that is a function of the class and other arguments.
respects subclassing, it is called with the class it is called from.
'''
Zuerst werde ich es erklären a_normal_instance_method
. Dies wird genau als "InstanzmethodeWenn eine Instanzmethode verwendet wird, wird sie als Teilfunktion verwendet (im Gegensatz zu einer Gesamtfunktion, die im Quellcode für alle Werte definiert ist). Wenn sie verwendet wird, wird das erste der Argumente als Instanz vordefiniert des Objekts mit all seinen gegebenen Attributen.Es ist die Instanz des Objekts gebunden, und es muss von einer Instanz des Objekts aufgerufen werden.Typischerweise wird es auf verschiedene Attribute der Instanz zugreifen.
Dies ist beispielsweise eine Instanz einer Zeichenfolge:
', '
Wenn wir die Instanzmethode verwenden, join
auf dieser Zeichenfolge, um eine andere iterable zu verbinden,
es ist ganz offensichtlich eine Funktion der Instanz, zusätzlich dazu, dass sie eine Funktion der iterierbaren Liste ist, ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Instanzmethoden können über eine gepunktete Suche zur späteren Verwendung gebunden werden.
Zum Beispiel bindet dies die str.join
Methode zum ':'
Beispiel:
>>> join_with_colons = ':'.join
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:
>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Die statische Methode tut es nicht nimm die Instanz als Argument.
Es ist einer Modulebene-Funktion sehr ähnlich.
Eine Modulebene-Funktion muss jedoch im Modul vorhanden sein und speziell an andere Stellen importiert werden, an denen sie verwendet wird.
Wenn es jedoch an das Objekt angehängt ist, wird es dem Objekt auch bequem durch Importieren und Vererben folgen.
Ein Beispiel für eine statische Methode ist str.maketrans
, bewegt von der string
Modul in Python 3. Es macht eine Übersetzungstabelle geeignet für den Verbrauch von str.translate
. Es scheint ziemlich albern zu sein, wenn es aus einer Instanz einer Zeichenkette, wie unten gezeigt, verwendet wird, aber importiert die Funktion von der string
Modul ist eher ungeschickt, und es ist schön, es aus der Klasse zu nennen, wie in str.maketrans
# demonstrate same function whether called from instance or not:
>>> ', '.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 immer weniger nützlichen String-Modul importieren:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Eine Klassenmethode ähnelt einer Instanzmethode insofern, als sie ein implizites erstes Argument benötigt, aber anstatt die Instanz zu übernehmen, benötigt sie die Klasse. Diese werden häufig als alternative Konstruktoren für eine bessere semantische Verwendung verwendet und unterstützen die Vererbung.
Das kanonischste Beispiel einer eingebauten 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 haben möchten.)
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Wenn wir dict ableiten, können wir denselben Konstruktor verwenden, der eine Instanz der Unterklasse erstellt.
>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>
Siehe die Pandas Quellcode für andere ähnliche Beispiele alternativer Konstruktoren, und siehe auch die offizielle Python-Dokumentation zu classmethod
und staticmethod
.
@decorators wurden in Python hinzugefügt 2.4 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 je nach Argument eine Instanz einer anderen Implementierung einer Klasse zurückgibt), können Sie Folgendes tun:
class Cluster(object):
def _is_cluster_for(cls, name):
"""
see if this class is the cluster with this name
this is a classmethod
"""
return cls.__name__ == name
_is_cluster_for = classmethod(_is_cluster_for)
#static method
def getCluster(name):
"""
static factory method, should be in Cluster class
returns a cluster object for the given name
"""
for cls in Cluster.__subclasses__():
if cls._is_cluster_for(name):
return cls()
getCluster = staticmethod(getCluster)
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 intern die Klasse Cluster verwendet. Die Klassenmethode benötigt nur Informationen über die Klasse und keine Instanz des Objekts.
Ein weiterer Vorteil der _is_cluster_for
Methode Eine Klassenmethode ist so eine Unterklasse kann entscheiden, ihre Implementierung zu ändern, vielleicht weil es ziemlich generisch ist und mehr als einen Typ von Cluster behandeln kann, also nur den Namen der Klasse zu überprüfen wäre nicht genug.
Ich denke, eine bessere Frage ist "Wann würdest du @classmethod vs @staticmethod verwenden?"
@classmethod ermöglicht Ihnen den einfachen Zugriff auf private Member, die der Klassendefinition zugeordnet sind. Dies ist eine großartige Möglichkeit, Singletons oder Factory-Klassen zu erstellen, die die Anzahl der Instanzen der erstellten Objekte steuern.
@staticmethod bietet marginale Leistungssteigerungen, aber ich muss noch eine produktive Verwendung einer statischen Methode innerhalb einer Klasse sehen, die nicht als eigenständige Funktion außerhalb der Klasse erreicht werden kann.