wake-up-neo.com

Wann sollte ich @classmethod und wann def method (self) verwenden?

Bei der Integration einer Django App, die ich zuvor noch nicht verwendet habe, habe ich zwei verschiedene Methoden gefunden, um Funktionen in Klassen zu definieren. Der Autor scheint beide sehr absichtlich zu verwenden. Die erste ist eine, die ich selbst verwende viel:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

Der andere ist einer, den ich nicht benutze, hauptsächlich, weil ich nicht verstehe, wann ich ihn verwenden soll und wofür:

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

In den Python docs wird der Dekorator classmethod mit folgendem Satz erklärt:

Eine Klassenmethode empfängt die Klasse als implizites erstes Argument, genau wie eine Instanzmethode die Instanz empfängt.

Also denke ich, dass cls auf Dummy selbst verweist (das class, nicht die Instanz). Ich verstehe nicht genau, warum das existiert, weil ich das immer tun könnte:

type(self).do_something_with_the_class

Ist das nur aus Gründen der Klarheit, oder habe ich den wichtigsten Teil übersehen: gruselige und faszinierende Dinge, die ohne sie nicht möglich wären?

69
marue

Ihre Vermutung ist richtig - Sie verstehen , wie classmethods funktionieren.

Der Grund dafür ist, dass diese Methoden beide für eine Instanz OR für die Klasse) aufgerufen werden können (in beiden Fällen wird das Klassenobjekt als erstes Argument übergeben):

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

Über die Verwendung dieser in Instanzen: Es gibt mindestens zwei Hauptverwendungen für den Aufruf einer Klassenmethode in einer Instanz:

  1. self.some_function() ruft die Version von some_function für den tatsächlichen Typ von self auf und nicht die Klasse, in der dieser Aufruf zufällig auftritt (und benötigt keine Beachtung, wenn der Klasse wird umbenannt); und
  2. In Fällen, in denen some_function Erforderlich ist, um ein Protokoll zu implementieren, es jedoch nützlich ist, nur das Klassenobjekt aufzurufen.

Der Unterschied zu staticmethod: Es gibt eine andere Möglichkeit, Methoden zu definieren, die nicht auf Instanzdaten zugreifen, und zwar staticmethod. Das schafft eine Methode, die überhaupt kein implizites erstes Argument erhält; Dementsprechend werden keine Informationen über die Instanz oder Klasse weitergegeben, für die sie aufgerufen wurden.

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

Die Hauptverwendung, die ich dafür gefunden habe, besteht darin, eine vorhandene Funktion (die kein self erwartet) so anzupassen, dass sie eine Methode für eine Klasse (oder ein Objekt) ist.

63
Marcin