Was sind in Python „Klassenmethoden“ und „Instanzmethoden“?

37

Es gab eine Diskussion im Chat über eine Frage (die Frage selbst ist für diese irrelevant), die ergeben hat, dass ich Python möglicherweise überhaupt nicht kenne.

Obwohl sich die Terminologie in den verschiedenen Sprachen unterscheidet, können wir meiner Meinung nach Funktionen im Allgemeinen wie folgt einteilen:

  • [freie] Funktionen
  • statische Methoden / statische Elementfunktionen
  • nicht statische Methoden / nicht statische Elementfunktionen

Anscheinend gibt es in Python eine andere Art von Funktion, die nicht in die obigen Kategorien passt, eine Methode, die aber "ihre Klasse nicht kennt".

Was sind "Klassenmethoden" und "Instanzmethoden" in Python?

Leichtigkeit Rennen mit Monica
quelle
1
Wenn jemand an der Chat-Diskussion interessiert ist, beginne hier: chat.stackexchange.com/transcript/message/26479002#26479002
yannis
1
IMO eine bessere Antwort wird von einer anderen Stackexchange-Website bereitgestellt
Trevor Boyd Smith
Zu Ihrer Information, der Link ist unten in der Liste der akzeptierten Links angegeben ... aber ich denke, viele Leute werden den Link verpassen oder nie darauf zugreifen. Deshalb habe ich ihn hier oben kopiert.
Trevor Boyd Smith

Antworten:

49

Die kurze Antwort

  • Eine Instanzmethode kennt ihre Instanz (und daraus ihre Klasse)
  • Eine Klassenmethode kennt ihre Klasse
  • Eine statische Methode kennt ihre Klasse oder Instanz nicht

Die lange Antwort

Klassenmethoden

Eine Klassenmethode ist eine, die zur gesamten Klasse gehört. Es ist keine Instanz erforderlich. Stattdessen wird die Klasse automatisch als erstes Argument gesendet. Mit dem @classmethodDecorator wird eine Klassenmethode deklariert .

Beispielsweise:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Instanzmethoden

Auf der anderen Seite, eine Instanz - Methode erfordert eine Instanz, um sie zu nennen, und erfordert keinen Dekorateur. Dies ist bei weitem die gebräuchlichste Methode.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(Hinweis: Das obige ist mit python3; mit python2 wird ein etwas anderer Fehler angezeigt)

Statische Methoden

Eine statische Methode ähnelt einer Klassenmethode, ruft jedoch das Klassenobjekt nicht als automatischen Parameter ab. Es wird mit dem @staticmethodDekorateur erstellt.

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Dokumentationslinks

Hier sind Links zur entsprechenden python3-Dokumentation:

Die Dokumentation des Datenmodells enthält folgende Informationen zum Unterschied zwischen Klassenmethoden und statischen Methoden:

Statische Methodenobjekte Mit statischen Methodenobjekten können Sie die oben beschriebene Transformation von Funktionsobjekten in Methodenobjekte verhindern. Ein statisches Methodenobjekt ist ein Wrapper um ein beliebiges anderes Objekt, normalerweise ein benutzerdefiniertes Methodenobjekt. Wenn ein statisches Methodenobjekt aus einer Klasse oder einer Klasseninstanz abgerufen wird, ist das tatsächlich zurückgegebene Objekt das umschlossene Objekt, das keiner weiteren Transformation unterzogen wird. Statische Methodenobjekte sind selbst nicht aufrufbar, obwohl dies normalerweise die Objekte sind, die sie umschließen. Statische Methodenobjekte werden mit dem integrierten staticmethod () -Konstruktor erstellt.

Klassenmethodenobjekte Ein Klassenmethodenobjekt ist wie ein statisches Methodenobjekt ein Wrapper um ein anderes Objekt, der die Art und Weise ändert, in der dieses Objekt aus Klassen und Klasseninstanzen abgerufen wird. Das Verhalten von Klassenmethodenobjekten bei einem solchen Abruf ist oben unter „Benutzerdefinierte Methoden“ beschrieben. Klassenmethodenobjekte werden vom integrierten classmethod () -Konstruktor erstellt.

Verwandte Fragen

Bryan Oakley
quelle
4
@LightnessRacesinOrbit: Ich glaube nicht, dass statische Methoden in Python besonders häufig verwendet werden. Wenn ich mein System als Zufallsstichprobe verwende und alle Pakete durchsuche, die ich installiert habe, sind nur etwa 1% aller Methoden statische Methoden (was ehrlich gesagt mehr war, als ich erwartet hatte).
Bryan Oakley
1
"Statische Methoden" sind in der Regel ein Code-Geruch und werden beispielsweise von Gogole Python-Stilrichtlinien nicht empfohlen.
9000
3
Ich denke, die Antwort wäre besser, wenn sie die Aufmerksamkeit auf Unterklassen lenken würde, in denen Klassenmethoden eine gewisse Nützlichkeit erhalten.
Winston Ewert
1
@ user2357112: Ich habe einfach alle Instanzen von "^ def("und dann alle Instanzen von gezählt @staticmethod. Sehr unwissenschaftlich, aber wahrscheinlich im Ballpark.
Bryan Oakley
2
@ Kashyap: Das TL; DR gilt für den ersten Absatz. Ich denke, es funktioniert oben besser als unten.
Bryan Oakley
8

Was sind in Python „Klassenmethoden“ und „Instanzmethoden“?

  • Eine "Instanzmethode" verwendet die in der Instanz enthaltenen Informationen, um herauszufinden, welcher Wert zurückgegeben werden soll (oder welche Nebenwirkung zu erzielen ist). Diese sind sehr verbreitet.

  • Eine "Klassenmethode" verwendet Informationen über die Klasse (und nicht eine Instanz dieser Klasse), um ihre Funktion zu beeinflussen (normalerweise werden sie zum Erstellen neuer Instanzen als alternative Konstruktoren verwendet und sind daher nicht sehr verbreitet).

  • Eine "statische Methode" verwendet keine Informationen über die Klasse oder Instanz, um zu berechnen, was sie tut. Es ist in der Regel nur in der Klasse für die Bequemlichkeit. (Daher sind diese auch nicht sehr verbreitet.)

Eine Funktion von X

Denken Sie daran, Mathe-Klasse, "y ist eine Funktion von x f(x),?" Wenden wir das im Code an:

y = function(x)

Aus dem oben Gesagten ergibt sich, dass xsich Änderungen ändern ykönnen, wenn sich xÄnderungen ergeben. Das ist gemeint, wenn wir sagen, dass " yeine Funktion von x" ist.

Was wird ysein , wenn zist 1? 2? 'FooBarBaz'?

yist keine Funktion von z, zkann also alles sein und hat keinen Einfluss auf das Ergebnis der Funktion, vorausgesetzt unsere functionist eine reine Funktion. (Wenn es zals globale Variable zugreift , dann ist es keine reine Funktion - das ist, was mit funktionaler Reinheit gemeint ist.)

Beachten Sie beim Lesen der folgenden Beschreibungen Folgendes:

Instanzmethoden

Eine Instanzmethode ist , die Funktion ist eine Funktion von einer Instanz . Die Funktion akzeptiert die Instanz implizit als Argument und die Instanz wird von der Funktion verwendet, um die Ausgabe der Funktion zu bestimmen.

Ein eingebautes Beispiel für eine Instanzmethode ist str.lower:

>>> 'ABC'.lower()
'abc'

str.lower wird für die Instanz der Zeichenfolge aufgerufen und verwendet die in der Instanz enthaltenen Informationen, um herauszufinden, welche neue Zeichenfolge zurückgegeben werden soll.

Klassenmethoden:

Denken Sie daran, in Python ist alles ein Objekt. Das heißt, die Klasse ist ein Objekt und kann als Argument an eine Funktion übergeben werden.

Eine Klasse - Methode ist eine Funktion , die eine Funktion ist von der Klasse . Es akzeptiert die Klasse als Argument dafür.

Ein eingebautes Beispiel ist dict.fromkeys:

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

Die Funktion kennt implizit ihre eigene Klasse, die Funktion verwendet die Klasse, um die Ausgabe der Funktion zu beeinflussen, und erstellt aus dem Iterablen eine neue Klasse dieser Klasse. Ein OrderedDict demonstriert dies mit der gleichen Methode:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

Die Klassenmethode verwendet Informationen zur Klasse (und nicht zu einer Instanz dieser Klasse), um zu bestimmen, welcher Klassentyp zurückgegeben werden soll.

Statische Methoden

Sie erwähnen eine Methode, die "ihre Klasse nicht kennt" - dies ist eine statische Methode in Python. Es wird lediglich der Einfachheit halber an das Klassenobjekt angehängt. Es könnte optional eine separate Funktion in einem anderen Modul sein, aber seine Anrufsignatur wäre dieselbe.

Eine statische Methode ist weder eine Funktion der Klasse noch des Objekts.

Ein eingebautes Beispiel für eine statische Methode ist str.maketrans aus Python 3.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

Mit ein paar Argumenten wird ein Wörterbuch erstellt, das nicht von seiner Klasse abhängt.

Dies ist praktisch, da stres immer im globalen Namespace verfügbar ist, sodass Sie es problemlos mit der Übersetzungsfunktion verwenden können:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

In Python 2 müssen Sie über das stringModul darauf zugreifen :

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Beispiel

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Lasst uns instanziieren:

>>> instance = AClass()

Jetzt kann die Instanz alle Methoden aufrufen:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Die Klasse ist jedoch normalerweise nicht zum Aufrufen der Instanzmethode gedacht, obwohl erwartet wird, dass die anderen Methoden aufgerufen werden:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Sie müssten die Instanz explizit übergeben, um die Instanzmethode aufzurufen:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
Aaron Hall
quelle
"Dies ist eine statische Methode in Python. Sie wird lediglich der Einfachheit halber an das Klassenobjekt angehängt. Sie könnte optional eine separate Funktion in einem anderen Modul sein, aber ihre Aufrufsignatur wäre dieselbe." Scheint eher verwirrend als praktisch. Warum würden Sie einer Klasse eine Funktion zuordnen, wenn ihr Körper keine Ahnung von dieser Klasse haben würde?
Leichtigkeit Rennen mit Monica
@LightnessRacesinOrbit Ich habe auf jeden Punkt näher eingegangen
Aaron Hall
Persönlich habe ich es immer so gesehen, dass eine Instanzmethode eine Operation auf einer bestimmten Instanz ist, eine Klassenmethode eine Art Konstruktor (der Einfachheit halber nicht wie, MyClass(1,2,3)sondern wie MyClass.get_special(1,2,3)) und eine statische Methode als einfach eine normale Funktion, die sowieso alleine stehen könnte.
Zizouz212,
Ja, Klassenmethoden werden normalerweise für alternative Konstruktoren verwendet (siehe mein dict.fromkeys-Beispiel oben, siehe auch den pandas.DataFrame-Quellcode), aber das ist kein definierendes Merkmal. Manchmal muss ich nur von einer Methode aus auf Daten zugreifen, die auf Klassenebene gespeichert sind, ohne auf die Instanz zuzugreifen. Wenn Sie type (self) (oder noch schlimmer self .__ class__) aufrufen und self nicht direkt in einer Instanzmethode verwenden, ist dies ein gutes Zeichen, dass Sie es als Klassenmethode betrachten sollten. Da Klassenmethoden keine Instanzen benötigen, ist es einfacher, sie zu entfernen.
Aaron Hall
4
  • Eine "Instanzmethode" ist eine Methode, die das Instanzobjekt als ersten Parameter übergibt, der per Konvention aufgerufen wird self. Dies ist die Standardeinstellung.

  • Eine "statische Methode" ist eine Methode ohne den Anfangsparameter self. Dies wird mit dem Dekorator @staticmethod implementiert .

  • Eine "Klassenmethode" ist eine Methode, bei der der Anfangsparameter kein Instanzobjekt ist, sondern das Klassenobjekt ( was ein "Klassenobjekt" ist, erfahren Sie in diesem Teil der Python-Dokumentation ), das gemäß der Konvention aufgerufen wird cls. Dies wird mit dem @ classmethod decorator implementiert .

Die typische Verwendung des Begriffs "statische Methode" in C / C ++ / etc gilt sowohl für Python-Methoden "static" als auch für Python-Methoden "class", da diese beiden Methoden keinen Verweis auf die Instanz enthalten. In C / C ++ / etc haben Methoden normalerweise impliziten Zugriff auf alle Nicht-Instanz-Member / Methoden der Klasse, weshalb diese Unterscheidung wahrscheinlich nur in Sprachen wie Python / Ruby / etc vorhanden ist.

Ixrec
quelle
Hat eine statische Methode in C / C ++ einen Verweis auf das Klassenobjekt? Oder nur "Mitglieder" der Klasse? Können sie neue Mitglieder der Klasse erstellen? :)
Aaron Hall
3
@AaronHall In C / C ++ gibt es kein Klassenobjekt, und Sie benötigen keinen Verweis darauf, um statische Methoden aufzurufen. Du schreibst einfach Class::staticMethod()und das wars (solange es dir nicht verboten ist, es anzurufen, weil staticMethod()es privat ist oder so).
Ixrec