4626 Stimmen

Was ist der Unterschied zwischen @staticmethod und @classmethod in Python?

Was ist der Unterschied zwischen einer Methode dekoriert mit @staticmethod und einer Methode, die mit @classmethod dekoriert ist?

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

97voto

Tom Neyland Punkte 6749

Hier ist ein kurzer Artikel zu dieser Frage

@staticmethod Funktion ist nichts mehr als eine Funktion, die innerhalb einer Klasse definiert ist. Sie kann aufgerufen werden, ohne zuerst die Klasse instanziieren zu müssen. Der Begriff ist unveränderlich über Vererbung.

@classmethod Funktion kann ebenfalls aufgerufen werden, ohne die Klasse instanziieren zu müssen, aber ihre Definition folgt der Unterklasse, nicht der Elternklasse, über Vererbung. Das liegt daran, dass das erste Argument für @classmethod Funktion immer cls (Klasse) sein muss.

2 Stimmen

Bedeutet das also, dass ich mit Hilfe von staticmethod immer an die Elternklasse gebunden bin und mit classmethod an die Klasse, in der ich classmethod deklariere (in diesem Fall die Unterklasse)?

10 Stimmen

Nein. Durch die Verwendung einer statischen Methode sind Sie überhaupt nicht gebunden; es gibt keinen impliziten ersten Parameter. Durch die Verwendung der Klassenmethode erhalten Sie als impliziten ersten Parameter die Klasse, auf der Sie die Methode aufgerufen haben (wenn Sie sie direkt auf einer Klasse aufgerufen haben), oder die Klasse der Instanz, auf der Sie die Methode aufgerufen haben (wenn Sie sie auf einer Instanz aufgerufen haben).

9 Stimmen

Könnte ein wenig erweitert werden, um zu zeigen, dass durch die Angabe einer Klasse als ersten Argument Klassenmethoden direkten Zugriff auf andere Klassenattribute und -methoden haben, während statische Methoden dies nicht tun (sie müssten MyClass.attr dafür fest codieren)

75voto

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.

63voto

Gaurang Shah Punkte 10034

Ich habe damit begonnen, Programmiersprachen mit C++ zu lernen und dann Java und dann Python, und deshalb hat mich diese Frage auch sehr beschäftigt, bis ich die einfache Verwendung von jedem verstanden habe.

Klassenmethode: Python hat im Gegensatz zu Java und C++ kein Konstruktorüberladen. Und um dies zu erreichen, könnten Sie classmethod verwenden. Das folgende Beispiel wird dies erklären.

Angenommen, wir haben eine Person-Klasse, die zwei Argumente first_name und last_name annimmt und die Instanz von Person erstellt.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

Wenn nun die Anforderung besteht, dass Sie eine Klasse nur mit einem einzigen Namen erstellen müssen, nur einem first_name, können Sie dies in Python nicht tun.

Dies wird Ihnen einen Fehler geben, wenn Sie versuchen, ein Objekt (Instanz) zu erstellen.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

Sie könnten jedoch das Gleiche mit @classmethod wie unten erwähnt erreichen.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

Statische Methode: Dies ist eher einfach, sie ist nicht an eine Instanz oder Klasse gebunden und Sie können sie einfach mit dem Klassennamen aufrufen.

Angenommen, in obigem Beispiel benötigen Sie eine Validierung, dass first_name nicht mehr als 20 Zeichen haben darf, können Sie dies einfach tun.

@staticmethod  
def validate_name(name):
    return len(name) <= 20

und Sie könnten es einfach mit Klassenname aufrufen.

Person.validate_name("Gaurang Shah")

11 Stimmen

Es ist ein alter Beitrag, aber eine Pythonische Methode, um einen Konstruktor zu erreichen, der entweder einen oder zwei Argumente akzeptiert, wäre die Verwendung von def __init__(self, first_name, last_name="") anstelle von classmethod get_person. Auch das Ergebnis wird in diesem Fall genau das gleiche sein.

61voto

blue_note Punkte 25040

Nur das erste Argument unterscheidet sich:

  • normale Methode: das aktuelle Objekt wird automatisch als (zusätzliches) erstes Argument übergeben
  • classmethod: die Klasse des aktuellen Objekts wird automatisch als (zusätzliches) erstes Argument übergeben
  • staticmethod: keine zusätzlichen Argumente werden automatisch übergeben. Was du der Funktion übergibst, ist das, was du bekommst.

Genaues...

normale Methode

Die "Standard"-Methode, wie in jeder objektorientierten Sprache. Wenn eine Objektmethode aufgerufen wird, wird automatisch ein zusätzliches Argument self als erstes Argument übergeben. Das heißt, die Methode

def f(self, x, y)

muss mit 2 Argumenten aufgerufen werden. self wird automatisch übergeben, und es ist das Objekt selbst. Ähnlich wie das this, das magischerweise in z.B. java/c++ erscheint, nur in Python wird es explizit gezeigt.

eigentlich muss das erste Argument nicht unbedingt self genannt werden, aber es ist die Standardkonvention, also behalte es bei

Klassenmethode

Wenn die Methode dekoriert ist

@classmethod
def f(cls, x, y)

das automatisch bereitgestellte Argument ist nicht self, sondern die Klasse von self.

Statische Methode

Wenn die Methode dekoriert ist

@staticmethod
def f(x, y)

wird der Methode kein automatisches Argument übergeben. Es werden nur die Parameter übergeben, mit denen sie aufgerufen wird.

Verwendungen

  • classmethod wird hauptsächlich für alternative Konstruktoren verwendet.
  • staticmethod verwendet nicht den Zustand des Objekts oder sogar die Struktur der Klasse selbst. Es könnte eine Funktion außerhalb einer Klasse sein. Es wird nur innerhalb der Klasse platziert, um Funktionen mit ähnlicher Funktionalität zu gruppieren (zum Beispiel wie Javas Math Klassenstatikmethoden)

    Klasse Punkt def init(self, x, y): self.x = x self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """Das `cls` Argument ist die `Punkt` Klasse selbst"""
        return cls(radius * cos(angle), radius * sin(angle))
    
    @staticmethod
    def winkel(x, y):
        """dies könnte außerhalb der Klasse sein, aber wir platzieren es hier nur, 

    weil wir denken, dass es logisch mit der Klasse verwandt ist.""" return atan(y, x)

    p1 = Punkt(3, 2) p2 = Punkt.frompolar(3, pi/4)

    winkel = Punkt.winkel(3, 2)

0 Stimmen

Dies ist die beste Antwort unter allen oben genannten. Sie ist klar mit guten und prägnanten Beispielen. Die anderen Beispiele lassen einige Details aus.

0 Stimmen

Dies ist die einzige Antwort, die dieses Konzept sehr gut erklärt. Ich habe GraphQL für APIs in Python gelernt und einige verwenden classmethod, während andere staticmethod unter ihrer Klassenmutation verwenden. Dies brachte mich dazu, den Grund zu verstehen, warum sie auf diese Weise verwendet werden, und das hier hat wirklich Antworten auf meine Neugierde geliefert. Danke dir

48voto

Nathan Tregillus Punkte 5588

Ich denke, eine bessere Frage ist "Wann würden Sie @classmethod vs @staticmethod verwenden?"

@classmethod ermöglicht Ihnen einen einfachen Zugriff auf private Elemente, die der Klassendefinition zugeordnet sind. Dies ist eine großartige Möglichkeit, Singleton-Muster oder Factory-Klassen zu erstellen, die die Anzahl der erstellten Objektinstanzen steuern.

@staticmethod bietet marginale Leistungssteigerungen, aber ich habe noch keine produktive Verwendung einer statischen Methode innerhalb einer Klasse gesehen, die nicht als eigenständige Funktion außerhalb der Klasse erreicht werden könnte.

0 Stimmen

Diese Frage erwähnt den Zugriff auf private Klassenmember. Ich möchte betonen, dass (abhängig von Ihrer Definition von private) @staticmethods einen anderen Zugriffslevel zu @classmethods haben. Erstere sollten nicht auf private Klassenmember zugreifen.

CodeJaeger.com

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.

Powered by:

X