Ich bringe mir Python bei und meine letzte Lektion war, dass Python kein Java ist. Deshalb habe ich nur eine Weile damit verbracht, alle meine Klassenmethoden in Funktionen umzuwandeln.
Mir ist jetzt klar, dass ich für das, was ich mit static
Methoden in Java machen würde, keine Klassenmethoden verwenden muss , aber jetzt bin ich mir nicht sicher, wann ich sie verwenden würde. Alle Ratschläge, die ich zu Python Class-Methoden finden kann, beziehen sich auf Neulinge, wie ich sie meiden sollte, und die Standarddokumentation ist bei der Diskussion am undurchsichtigsten.
Hat jemand ein gutes Beispiel für die Verwendung einer Klassenmethode in Python oder kann mir zumindest jemand sagen, wann Klassenmethoden sinnvoll eingesetzt werden können?
quelle
obj.cls_mthd(...)
odertype(obj).cls_mthd(...)
?Factory-Methoden (alternative Konstruktoren) sind in der Tat ein klassisches Beispiel für Klassenmethoden.
Grundsätzlich sind Klassenmethoden immer dann geeignet, wenn Sie eine Methode haben möchten, die natürlich in den Namespace der Klasse passt, aber keiner bestimmten Instanz der Klasse zugeordnet ist.
Als Beispiel im hervorragenden Unipath- Modul:
Aktuelles Verzeichnis
Path.cwd()
Path("/tmp/my_temp_dir")
. Dies ist eine Klassenmethode..chdir()
Da das aktuelle Verzeichnis prozessweit ist, verfügt die
cwd
Methode über keine bestimmte Instanz, der sie zugeordnet werden sollte. Ändern Sie jedoch dascwd
in das Verzeichnis eines bestimmtenPath
Instanz sollte jedoch tatsächlich eine Instanzmethode sein.Hmmm ... wie
Path.cwd()
es tatsächlich einePath
Instanz zurückgibt , könnte es als Fabrikmethode angesehen werden ...quelle
Stellen Sie sich das so vor: Normale Methoden sind nützlich, um die Details des Versands auszublenden: Sie können eingeben,
myobj.foo()
ohne sich Gedanken darüber zu machen, ob diefoo()
Methode von dermyobj
Klasse des Objekts oder einer seiner übergeordneten Klassen implementiert wird . Klassenmethoden sind genau analog dazu, aber stattdessen mit dem Klassenobjekt: Sie können aufrufen,MyClass.foo()
ohne sich Gedanken darüber machen zu müssen, obfoo()
sie speziell von implementiert werden,MyClass
weil sie eine eigene spezielle Version benötigen, oder ob die übergeordnete Klasse den Aufruf verarbeiten kann.Klassenmethoden sind wichtig, wenn Sie eine Einrichtung oder Berechnung durchführen, die der Erstellung einer tatsächlichen Instanz vorausgeht , da Sie die Instanz offensichtlich erst dann als Versandpunkt für Ihre Methodenaufrufe verwenden können, wenn die Instanz vorhanden ist. Ein gutes Beispiel finden Sie im SQLAlchemy-Quellcode. Schauen Sie sich die
dbapi()
Klassenmethode unter folgendem Link an:https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47
Sie können sehen, dass die
dbapi()
Methode, mit der ein Datenbank-Backend die herstellerspezifische Datenbankbibliothek importiert, die sie bei Bedarf benötigt, eine Klassenmethode ist, da sie ausgeführt werden muss, bevor Instanzen einer bestimmten Datenbankverbindung erstellt werden können. Dies ist jedoch nicht möglich eine einfache oder statische Funktion sein, weil sie möchte, dass sie andere unterstützende Methoden aufrufen kann, die in ähnlicher Weise möglicherweise spezifischer in Unterklassen als in ihrer übergeordneten Klasse geschrieben werden müssen. Und wenn Sie an eine Funktion oder statische Klasse senden, "vergessen" Sie und verlieren das Wissen darüber, welche Klasse die Initialisierung durchführt.quelle
Ich wollte kürzlich eine sehr leichte Protokollierungsklasse, die je nach Protokollierungsstufe, die programmgesteuert festgelegt werden kann, unterschiedliche Ausgabemengen ausgibt. Ich wollte die Klasse jedoch nicht jedes Mal instanziieren, wenn ich eine Debugging-Nachricht, einen Fehler oder eine Warnung ausgeben wollte. Ich wollte aber auch die Funktionsweise dieser Protokollierungsfunktion zusammenfassen und ohne die Deklaration von Globals wiederverwendbar machen.
Also habe ich Klassenvariablen und den
@classmethod
Dekorator verwendet, um dies zu erreichen.Mit meiner einfachen Protokollierungsklasse könnte ich Folgendes tun:
Wenn ich dann in meinem Code eine Reihe von Debugging-Informationen ausspucken wollte, musste ich einfach codieren
Fehler könnten ausgegeben werden
In der "Produktions" -Umgebung kann ich angeben
und jetzt wird nur die Fehlermeldung ausgegeben. Die Debug-Nachricht wird nicht gedruckt.
Hier ist meine Klasse:
Und ein Code, der es nur ein bisschen testet:
quelle
Alternative Konstruktoren sind das klassische Beispiel.
quelle
Wenn sich ein Benutzer auf meiner Website anmeldet, wird ein User () -Objekt aus dem Benutzernamen und dem Kennwort instanziiert.
Wenn ich ein Benutzerobjekt benötige, ohne dass der Benutzer zum Anmelden da ist (z. B. möchte ein Administrator möglicherweise ein anderes Benutzerkonto löschen, daher muss ich diesen Benutzer instanziieren und seine Löschmethode aufrufen):
Ich habe Klassenmethoden, um das Benutzerobjekt zu greifen.
quelle
Ich denke, die klarste Antwort ist die von AmanKow . Es läuft darauf hinaus, wie Sie Ihren Code organisieren möchten. Sie können alles als Funktionen auf Modulebene schreiben, die in den Namespace des Moduls eingeschlossen sind, d. H.
Der obige Verfahrenscode ist nicht gut organisiert, da Sie sehen können, dass es nach nur 3 Modulen verwirrend wird. Was macht jede Methode? Sie können lange beschreibende Namen für Funktionen verwenden (wie in Java), aber Ihr Code wird sehr schnell nicht mehr verwaltet.
Die objektorientierte Methode besteht darin, Ihren Code in verwaltbare Blöcke aufzuteilen, dh Klassen und Objekte und Funktionen können Objektinstanzen oder Klassen zugeordnet werden.
Mit Klassenfunktionen erhalten Sie eine andere Unterteilungsebene in Ihrem Code als mit Funktionen auf Modulebene. Sie können also verwandte Funktionen innerhalb einer Klasse gruppieren, um sie spezifischer für eine Aufgabe zu machen, die Sie dieser Klasse zugewiesen haben. Sie können beispielsweise eine Datei-Dienstprogrammklasse erstellen:
Diese Methode ist flexibler und wartbarer, Sie gruppieren Funktionen und es ist offensichtlicher, was jede Funktion tut. Außerdem verhindern Sie Namenskonflikte, z. B. kann die Funktionskopie in einem anderen importierten Modul (z. B. Netzwerkkopie) vorhanden sein, das Sie in Ihrem Code verwenden. Wenn Sie also den vollständigen Namen FileUtil.copy () verwenden, entfernen Sie das Problem und beide Kopierfunktionen kann nebeneinander verwendet werden.
quelle
FileUtil
Klassenmethoden als Funktionen einesfile_util
Moduls replizieren würden, wäre dies vergleichbar und würde OOP nicht missbrauchen, wenn tatsächlich keine Objekte vorhanden sind (tatsächlich könnten Sie argumentieren, dass dies vorzuziehen ist, da Sie keine oder keinefrom file_util import FileUtil
andere Ausführlichkeit haben). Namenskonflikte können im Verfahrenscode ebenfalls vermieden werden, indemimport file_util
stattdessen stattfrom file_util import ...
.Ehrlich? Ich habe nie eine Verwendung für staticmethod oder classmethod gefunden. Ich habe noch keine Operation gesehen, die nicht mit einer globalen Funktion oder einer Instanzmethode ausgeführt werden kann.
Es wäre anders, wenn Python private und geschützte Mitglieder verwenden würde, ähnlich wie Java. In Java benötige ich eine statische Methode, um auf die privaten Mitglieder einer Instanz zugreifen zu können. In Python ist das selten notwendig.
Normalerweise sehe ich Leute, die statische Methoden und Klassenmethoden verwenden, wenn sie wirklich nur die Namespaces auf Modulebene von Python besser verwenden müssen.
quelle
Sie können damit generische Klassenmethoden schreiben, die Sie mit jeder kompatiblen Klasse verwenden können.
Beispielsweise:
Wenn Sie nicht verwenden
@classmethod
, können Sie dies mit dem Schlüsselwort self tun, es wird jedoch eine Instanz von Class benötigt:quelle
Ich habe früher mit PHP gearbeitet und mich kürzlich gefragt, was mit dieser Klassenmethode los ist. Das Python-Handbuch ist sehr technisch und in Worten sehr kurz, daher hilft es nicht, diese Funktion zu verstehen. Ich habe gegoogelt und gegoogelt und eine Antwort gefunden -> http://code.anjanesh.net/2007/12/python-classmethods.html .
Wenn Sie faul sind, darauf zu klicken. Meine Erklärung ist kürzer und unten. :) :)
In PHP (vielleicht kennen nicht alle von Ihnen PHP, aber diese Sprache ist so einfach, dass jeder verstehen sollte, wovon ich spreche) haben wir statische Variablen wie diese:
Die Ausgabe erfolgt in beiden Fällen 20.
In Python können wir jedoch @classmethod decorator hinzufügen, und daher ist es möglich, Ausgabe 10 bzw. 20 zu haben. Beispiel:
Klug, nicht wahr?
quelle
B.setInnerVar(20)
wurde, es10
zweimal gedruckt wird (anstatt beim zweiten echoInnerBar () -Aufruf einen Fehler zu geben, für den noinner_var
definiert wurde.Klassenmethoden liefern einen "semantischen Zucker" (ich weiß nicht, ob dieser Begriff weit verbreitet ist) - oder "semantische Bequemlichkeit".
Beispiel: Sie haben eine Reihe von Klassen, die Objekte darstellen. Vielleicht möchten Sie die Klassenmethode haben
all()
oderfind()
schreibenUser.all()
oderUser.find(firstname='Guido')
. Das könnte natürlich mit Funktionen auf Modulebene geschehen ...quelle
Was mich gerade von Ruby getroffen hat, ist diese sogenannte Klasse und eine sogenannte Instanzmethode nur eine Funktion mit semantischer Bedeutung ist, die auf ihren ersten Parameter angewendet wird, der stillschweigend übergeben wird, wenn die Funktion als Methode von aufgerufen wird ein Objekt (dh
obj.meth()
).Normalerweise muss dieses Objekt eine Instanz sein, aber der
@classmethod
Methodendekorator ändert die Regeln, um eine Klasse zu übergeben. Sie können eine Klassenmethode für eine Instanz aufrufen (es ist nur eine Funktion) - das erste Argument ist ihre Klasse.Weil es nur ein ist Funktion handelt , kann sie in einem bestimmten Bereich (dh einer
class
Definition) nur einmal deklariert werden . Es folgt daher als Überraschung für einen Rubyisten, dass Sie keine Klassenmethode und keine Instanzmethode mit demselben Namen haben können .Bedenken Sie:
Du kannst anrufen
foo
eine InstanzAber nicht in einer Klasse:
Fügen Sie nun hinzu
@classmethod
:Das Aufrufen einer Instanz übergibt jetzt ihre Klasse:
ebenso wie das Aufrufen einer Klasse:
Es ist nur die Konvention, die vorschreibt, dass wir
self
für dieses erste Argument eine Instanzmethode verwenden undcls
eine Klassenmethode verwenden. Ich habe beides hier nicht verwendet, um zu veranschaulichen, dass es nur ein Argument ist. In Rubyself
ist ein Schlüsselwort.Kontrast zu Ruby:
Die Python-Klassenmethode ist nur eine dekorierte Funktion, und Sie können dieselben Techniken verwenden, um Ihre eigenen Dekoratoren zu erstellen . Eine dekorierte Methode umschließt die reale Methode (im Falle, dass
@classmethod
sie das zusätzliche Klassenargument übergibt). Die zugrunde liegende Methode ist immer noch vorhanden, versteckt, aber immer noch zugänglich .Fußnote: Ich habe dies geschrieben, nachdem ein Namenskonflikt zwischen einer Klassen- und einer Instanzmethode meine Neugier geweckt hat. Ich bin weit entfernt von einem Python-Experten und hätte gerne Kommentare, wenn dies falsch ist.
quelle
super()
). AFICT, die "Magie" passiert, wenn ein Attribut gesetzt oder gelesen wird. Der Aufrufobj.meth(arg)
in Python (im Gegensatz zu Ruby) bedeutet einfach(obj.meth)(arg)
. Nichts wird stillschweigend irgendwohin übergeben,obj.meth
sondern ist nur ein aufrufbares Objekt, das ein Argument weniger akzeptiert als die Funktion, aus der es erstellt wurde.obj.meth
bedeutet wiederum einfachgetattr(obj, "meth")
.Dies ist ein interessantes Thema. Ich gehe davon aus, dass die Python-Klassenmethode eher wie ein Singleton als wie eine Factory funktioniert (die eine produzierte Instanz einer Klasse zurückgibt). Der Grund, warum es sich um ein Singleton handelt, besteht darin, dass ein gemeinsames Objekt (das Wörterbuch) nur einmal für die Klasse erstellt wird, das jedoch von allen Instanzen gemeinsam genutzt wird.
Um dies hier zu veranschaulichen, ist ein Beispiel. Beachten Sie, dass alle Instanzen einen Verweis auf das einzelne Wörterbuch haben. Dies ist kein Factory-Muster, wie ich es verstehe. Dies ist wahrscheinlich sehr einzigartig für Python.
quelle
Ich habe mir einige Male die gleiche Frage gestellt. Und obwohl die Jungs hier versucht haben, es zu erklären, ist meiner Meinung nach die beste (und einfachste) Antwort, die ich gefunden habe, die Beschreibung der Class-Methode in der Python-Dokumentation.
Es wird auch auf die statische Methode verwiesen. Und falls jemand bereits Instanzmethoden kennt (was ich annehme), könnte diese Antwort das letzte Stück sein, um alles zusammenzufügen ...
Weitere und ausführlichere Informationen zu diesem Thema finden Sie auch in der Dokumentation: Die Standardtyphierarchie (scrollen Sie nach unten zum Abschnitt Instanzmethoden ).
quelle
@classmethod
kann nützlich sein, um Objekte dieser Klasse einfach von externen Ressourcen aus zu instanziieren. Folgendes berücksichtigen:Dann in einer anderen Datei:
Der Zugriff auf inst.x ergibt den gleichen Wert wie die Einstellungen ['x'].
quelle
Eine Klasse definiert natürlich eine Reihe von Instanzen. Und die Methoden einer Klasse arbeiten an den einzelnen Instanzen. Die Klassenmethoden (und Variablen) sind ein Ort, an dem andere Informationen, die sich auf die Menge der Instanzen beziehen, insgesamt aufgehängt werden können.
Wenn Ihre Klasse beispielsweise eine Gruppe von Schülern definiert, möchten Sie möglicherweise Klassenvariablen oder Methoden, die Dinge wie die Gruppe von Noten definieren, zu denen die Schüler gehören können.
Sie können auch Klassenmethoden verwenden, um Werkzeuge für die Arbeit am gesamten Satz zu definieren. Beispielsweise kann Student.all_of_em () alle bekannten Schüler zurückgeben. Wenn Ihre Instanz mehr Struktur als nur eine Menge hat, können Sie natürlich Klassenmethoden bereitstellen, um diese Struktur zu kennen. Students.all_of_em (Klasse = 'Junioren')
Techniken wie diese führen dazu, dass Mitglieder der Instanz in Datenstrukturen gespeichert werden, die in Klassenvariablen verwurzelt sind. Sie müssen darauf achten, dass die Speicherbereinigung dann nicht frustriert wird.
quelle