oop vs python3 - Was ist der Unterschied zwischen @staticmethod und @classmethod?




11 Answers

Eine statische Methode ist eine Methode, die nichts über die Klasse oder Instanz weiß, für die sie aufgerufen wurde. Es werden nur die übergebenen Argumente abgerufen, kein implizites erstes Argument. Es ist im Grunde in Python unbrauchbar - Sie können statt einer statischen Methode nur eine Modulfunktion 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 übergeben. Dies ist nützlich, wenn Sie möchten, dass die Methode eine Factory für die Klasse ist: Da sie die eigentliche Klasse als erstes Argument abruft, können Sie immer die richtige Klasse instanziieren, selbst 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:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
init call use

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




Offizielle Python-Dokumente:

@classmethod

Eine Klassenmethode empfängt die Klasse als implizites erstes Argument, genau wie eine Instanzmethode die Instanz. Um eine Klassenmethode zu deklarieren, verwenden Sie diese Redewendung:

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

Das @classmethod Formular ist ein Funktionsdekorator - Details finden Sie in der Beschreibung der Funktionsdefinitionen in Funktionsdefinitionen .

Es kann entweder für die Klasse (wie Cf() ) oder für eine Instanz (wie C().f() ) aufgerufen werden. Die Instanz wird mit Ausnahme ihrer Klasse ignoriert. Wenn eine Klassenmethode für eine abgeleitete Klasse aufgerufen wird, wird das abgeleitete Klassenobjekt als implizites erstes Argument übergeben.

Klassenmethoden unterscheiden sich von statischen C ++ - oder Java-Methoden. Wenn Sie diese staticmethod() , staticmethod() Sie staticmethod() in diesem Abschnitt.

@staticmethod

Eine statische Methode erhält kein implizites erstes Argument. Verwenden Sie diesen Ausdruck, um eine statische Methode zu deklarieren:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

Das @staticmethod Formular ist ein Funktionsdekorator - Details finden Sie in der Beschreibung der Funktionsdefinitionen in Funktionsdefinitionen .

Es kann entweder für die Klasse (wie Cf() ) oder für eine Instanz (wie C().f() ) aufgerufen werden. Die Instanz wird mit Ausnahme ihrer Klasse ignoriert.

Statische Methoden in Python ähneln denen in Java oder C ++. Für ein fortgeschritteneres Konzept siehe classmethod() in diesem Abschnitt.




Um zu entscheiden, ob Sie @staticmethod oder @classmethod verwenden @staticmethod @classmethod Sie in Ihre Methode schauen. 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.

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



@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 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 Verwendung der _is_cluster_for Methode zu einer Klassenmethode ist, dass eine Unterklasse entscheiden kann, ihre Implementierung zu ändern. Möglicherweise ist sie ziemlich generisch und kann mit mehr als einem Clustertyp arbeiten. Daher reicht es nicht aus, nur den Namen der Klasse zu überprüfen.




Statische Methoden:

  • Einfache Funktionen ohne Selbstargument.
  • Bearbeiten Sie Klassenattribute. nicht auf Instanzattributen.
  • Kann durch Klasse und Instanz aufgerufen werden.
  • Die eingebaute Funktion staticmethod () wird verwendet, um sie zu erstellen.

Vorteile statischer Methoden:

  • Es lokalisiert den Funktionsnamen im Klassenbereich
  • Dadurch wird der Funktionscode näher an den Verwendungsort verschoben
  • Bequemer zu importieren gegenüber Funktionen auf Modulebene, da nicht jede Methode speziell importiert werden muss

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    

Klassenmethoden:

  • Funktionen mit dem ersten Argument als Klassenname.
  • Kann durch Klasse und Instanz aufgerufen werden.
  • Diese werden mit der eingebauten Funktion classmethod erstellt.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    



Der definitive Leitfaden zur Verwendung von statischen, Klassen- oder abstrakten Methoden in Python ist ein guter Link zu diesem Thema. Fassen Sie ihn wie folgt zusammen.

@staticmethod Funktion @staticmethod ist nichts anderes als eine in einer Klasse definierte Funktion. Es ist aufrufbar, ohne die Klasse zuerst zu instanziieren. Seine Definition ist durch Vererbung unveränderlich.

  • Python muss keine gebundene Methode für ein Objekt instanziieren.
  • Es erleichtert die Lesbarkeit des Codes und hängt nicht vom Zustand des Objekts selbst ab.

@classmethod Funktion kann auch @classmethod werden, ohne die Klasse zu instanziieren, ihre Definition folgt jedoch der Unterklasse, nicht der übergeordneten Klasse, über die Vererbung. Sie kann von der Unterklasse überschrieben werden. @classmethod daran, dass das erste Argument für die @classmethod class- @classmethod immer cls (class) sein muss.

  • Factory-Methoden , die zum Erstellen einer Instanz für eine Klasse verwendet werden, z. B. mit einer Art Vorverarbeitung.
  • Statische Methoden, die statische Methoden aufrufen : Wenn Sie statische Methoden in mehrere statische Methoden aufteilen, sollten Sie den Klassennamen nicht fest codieren, sondern Klassenmethoden verwenden



Eine weitere Überlegung in Bezug auf staticmethod vs. classmethod ist die Vererbung. Angenommen, Sie haben folgende Klasse:

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

Und dann möchten Sie bar() in einer Kinderklasse überschreiben:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

Dies funktioniert, beachten Sie jedoch, dass die bar() Implementierung in der Foo2 Klasse ( Foo2 ) Foo2 nichts mehr ausnutzt, was für diese Klasse spezifisch ist. Foo2 , Foo2 hatte eine Methode namens magic() , die Sie in der Foo2 Implementierung von bar() möchten:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

Die Problemumgehung hier wäre, Foo2.magic() in bar() Foo2.magic() , aber Sie wiederholen sich dann (wenn sich der Name von Foo2 ändert, müssen Sie daran denken, diese bar() -Methode zu aktualisieren).

Für mich ist dies ein leichter Verstoß gegen das Open / Closed-Prinzip , da eine Entscheidung in Foo Ihre Fähigkeit beeinträchtigt, gängigen Code in einer abgeleiteten Klasse umzuwandeln (dh, er ist weniger für Erweiterungen geeignet). Wenn bar() eine classmethod wäre, classmethod wir in Ordnung:

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

Gibt: In Foo2 MAGIC




Lassen Sie mich zuerst die Ähnlichkeit zwischen einer Methode, die mit @classmethod vs @staticmethod dekoriert ist, erklären.

Ähnlichkeit: Beide können für die Klasse selbst und nicht nur für die Instanz der Klasse aufgerufen werden. Beide sind also gewissermaßen die Methoden von Class .

Unterschied: Eine Klassenmethode erhält die Klasse selbst als erstes Argument, eine statische Methode jedoch nicht.

Eine statische Methode ist also gewissermaßen nicht an die Klasse selbst gebunden und hängt nur deshalb, weil sie eine verwandte Funktionalität hat.

class C(object):
    @classmethod
    def fun(cls, arg1, arg2, ...):
       ....

fun: function that needs to be converted into a class method
returns: a class method for function.



@classmethod: kann verwendet werden, um einen gemeinsam genutzten globalen Zugriff auf alle Instanzen dieser Klasse zu erstellen ... wie das Aktualisieren eines Datensatzes durch mehrere Benutzer. Ich habe insbesondere festgestellt, dass er auch beim Erstellen von Singletons ful verwendet wird. )

@static-Methode: hat nichts mit der Klasse oder Instanz zu tun, die mit ... verbunden ist, aber für die Lesbarkeit kann eine statische Methode verwendet werden




Klassenmethoden werden, wie der Name schon sagt, dazu verwendet, Änderungen an Klassen und nicht an den Objekten vorzunehmen. Um Änderungen an Klassen vorzunehmen, ändern sie die Klassenattribute (nicht Objektattribute), da Sie Klassen so aktualisieren. Dies ist der Grund dafür, dass Klassenmethoden die Klasse (die herkömmlicherweise mit 'cls' bezeichnet wird) als erstes Argument verwenden.

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

Statische Methoden hingegen werden verwendet, um Funktionalitäten auszuführen, die nicht an die Klasse gebunden sind, dh sie lesen oder schreiben keine Klassenvariablen. Daher verwenden statische Methoden Klassen nicht als Argumente. Sie werden verwendet, damit Klassen Funktionen ausführen können, die nicht direkt mit dem Zweck der Klasse zusammenhängen.

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."



#!/usr/bin/python
#coding:utf-8

class Demo(object):
    def __init__(self,x):
        self.x = x

    @classmethod
    def addone(self, x):
        return x+1

    @staticmethod
    def addtwo(x):
        return x+2

    def addthree(self, x):
        return x+3

def main():
    print Demo.addone(2)
    print Demo.addtwo(2)

    #print Demo.addthree(2) #Error
    demo = Demo(2)
    print demo.addthree(2)


if __name__ == '__main__':
    main()



Related