Ich bin ein Java-Entwickler, der mit Python ein- und ausgeschaltet hat. Ich bin kürzlich auf diesen Artikel gestoßen, in dem häufige Fehler erwähnt werden, die Java-Programmierer machen, wenn sie Python lernen. Der erste fiel mir auf:
Eine statische Methode in Java wird nicht in eine Python-Klassenmethode übersetzt. Natürlich führt dies zu mehr oder weniger demselben Effekt, aber das Ziel einer Klassenmethode besteht darin, etwas zu tun, das in Java normalerweise nicht einmal möglich ist (wie das Erben eines nicht standardmäßigen Konstruktors). Die idiomatische Übersetzung einer statischen Java-Methode ist normalerweise eine Funktion auf Modulebene, keine Klassenmethode oder statische Methode. (Und statische Endfelder sollten in Konstanten auf Modulebene übersetzt werden.)
Dies ist kein großes Leistungsproblem, aber ein Python-Programmierer, der mit Java-Idiom-Code wie diesem arbeiten muss, wird durch die Eingabe von Foo.Foo.someMethod ziemlich irritiert, wenn es nur Foo.someFunction sein sollte. Beachten Sie jedoch, dass das Aufrufen einer Klassenmethode eine zusätzliche Speicherzuweisung beinhaltet, die beim Aufrufen einer statischen Methode oder Funktion nicht erfolgt.
Oh, und all diese Foo.Bar.Baz-Attributketten sind auch nicht kostenlos. In Java werden diese gepunkteten Namen vom Compiler nachgeschlagen, sodass es zur Laufzeit wirklich egal ist, wie viele davon Sie haben. In Python werden die Suchvorgänge zur Laufzeit ausgeführt, sodass jeder Punkt zählt. (Denken Sie daran, dass in Python "Flat ist besser als verschachtelt", obwohl es eher mit "Lesbarkeitszählungen" und "Einfach ist besser als komplex" zu tun hat, als mit Leistung.)
Ich fand das etwas seltsam, weil die Dokumentation für staticmethod lautet:
Statische Methoden in Python ähneln denen in Java oder C ++. Siehe auch classmethod () für eine Variante, die zum Erstellen alternativer Klassenkonstruktoren nützlich ist.
Noch rätselhafter ist, dass dieser Code:
class A:
def foo(x):
print(x)
A.foo(5)
Schlägt in Python 2.7.3 wie erwartet fehl, funktioniert aber in 3.2.3 einwandfrei (obwohl Sie die Methode nicht für eine Instanz von A aufrufen können, sondern nur für die Klasse.)
Es gibt also drei Möglichkeiten, statische Methoden zu implementieren (vier, wenn Sie mit der Klassenmethode zählen), jede mit subtilen Unterschieden, von denen eine scheinbar nicht dokumentiert ist. Dies scheint im Widerspruch zu Pythons Mantra zu stehen. Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun. Welche Redewendung ist die pythonischste? Was sind die Vor- und Nachteile von jedem?
Folgendes verstehe ich bisher:
Modulfunktion:
- Vermeidet das Problem Foo.Foo.f ()
- Verschmutzt den Namespace des Moduls mehr als die Alternativen
- Keine Vererbung
statische Methode:
- Hält Funktionen, die sich auf die Klasse beziehen, innerhalb der Klasse und außerhalb des Modul-Namespace.
- Ermöglicht das Aufrufen der Funktion für Instanzen der Klasse.
- Unterklassen können die Methode überschreiben.
Klassenmethode:
- Identisch mit staticmethod, übergibt aber auch die Klasse als erstes Argument.
Normale Methode (nur Python 3) :
- Identisch mit staticmethod, kann die Methode jedoch nicht für Instanzen der Klasse aufrufen.
Überdenke ich das? Ist das kein Problem? Bitte helfen Sie!
quelle
from Foo import *
wird davon abgeraten. Wenn die Funktionen modulintern und nicht Teil der öffentlichen API sein sollen, können Sie sie mit einem führenden Unterstrich benennen und werden dabei nicht importiertfrom Foo import *
.If the functions are meant to be used, they're not polluting the namespace, they're using it just as it should be used.
Wenn das umweltschädlich ist, warum dann überhaupt einen Namespace haben, wenn Sie ihn nur vermeiden wollen?Tolle Antwort von BrenBarn , aber ich würde "Wenn es keinen Zugriff auf die Klasse oder die Instanz benötigt, machen Sie es zu einer Funktion" ändern , um :
‚Wenn es keinen Zugriff auf die Klasse benötigen oder die Instanz ... aber ist thematisch in Bezug auf die Klasse (typisches Beispiel: Hilfsfunktionen und Konvertierungsfunktionen von anderen Klassenmethoden verwendet oder durch alternative Konstrukteuren verwendet wird ), dann verwenden static
sonst mach es a Modulfunktion
quelle
make_from_XXX()
klingt wie eine alternative Konstruktor , so dass sie paßt nicht richtig als static.datetime
Modul: Es würde weniger Hinweise geben,datetime.fromtimestamp()
die auf keiner alten Ganzzahl aufgerufen werden sollen.fromtimestamp()
Verhalten. Ich denke, dasfromtimestamp()
sollte hier wirklich eine Klassenmethode sein, keine statische Methode.Dies ist nicht wirklich eine Antwort, sondern ein langer Kommentar:
Ich werde versuchen zu erklären, was hier passiert.
Dies ist streng genommen ein Missbrauch des "normalen" Instanzmethodenprotokolls.
Was Sie hier definieren, ist eine Methode, aber mit dem ersten (und einzigen) Parameter nicht benannt
self
, sondernx
. Natürlich können Sie die Methode in einer Instanz vonA
aufrufen, aber Sie müssen sie folgendermaßen aufrufen:oder
Daher wird die Instanz der Funktion als erstes Argument übergeben.
Die Möglichkeit, reguläre Methoden über die Klasse aufzurufen, war schon immer vorhanden und funktioniert von
Wenn Sie hier die Methode der Klasse und nicht die Instanz aufrufen, wird der erste Parameter nicht automatisch angegeben, sondern Sie müssen ihn angeben.
Solange dies eine Instanz von ist
A
, ist alles in Ordnung. Etwas anderes zu geben ist IMO ein Missbrauch des Protokolls und damit der Unterschied zwischen Py2 und Py3:In Py2
A.foo
in eine ungebundene Methode umgewandelt und erfordert daher, dass das erste Argument eine Instanz der Klasse ist, in der es "lebt". Das Aufrufen mit etwas anderem schlägt fehl.In Py3 wurde diese Prüfung gelöscht und
A.foo
ist nur das ursprüngliche Funktionsobjekt. Sie können es also mit allem als erstem Argument bezeichnen, aber ich würde es nicht tun. Der erste Parameter einer Methode sollte immer benannt seinself
und die Semantik von habenself
.quelle
Die beste Antwort hängt davon ab, wie die Funktion verwendet wird. In meinem Fall schreibe ich Anwendungspakete, die in Jupyter-Notizbüchern verwendet werden. Mein Hauptziel ist es, dem Benutzer die Sache zu erleichtern.
Der Hauptvorteil von Funktionsdefinitionen besteht darin, dass der Benutzer seine definierende Datei mit dem Schlüsselwort "as" importieren kann. Auf diese Weise kann der Benutzer die Funktionen auf dieselbe Weise aufrufen wie eine Funktion in numpy oder matplotlib.
Einer der Nachteile von Python ist, dass Namen nicht gegen weitere Zuweisungen geschützt werden können. Wenn jedoch "import numpy as np" oben im Notizbuch angezeigt wird, ist dies ein starker Hinweis darauf, dass "np" nicht als allgemeiner Variablenname verwendet werden sollte. Sie können das Gleiche natürlich mit Klassennamen erreichen, aber die Vertrautheit der Benutzer ist sehr wichtig.
In den Paketen bevorzuge ich jedoch statische Methoden. Meine Softwarearchitektur ist objektorientiert und ich schreibe mit Eclipse, das ich für mehrere Zielsprachen verwende. Es ist praktisch, die Quelldatei zu öffnen und die Klassendefinition auf der obersten Ebene, die auf einer Ebene eingerückten Methodendefinitionen usw. anzuzeigen. Die Zielgruppe für den Code auf dieser Ebene sind hauptsächlich andere Analysten und Entwickler. Daher ist es besser, sprachspezifische Redewendungen zu vermeiden.
Ich habe nicht viel Vertrauen in die Python-Namespace-Verwaltung, insbesondere wenn Entwurfsmuster verwendet werden, bei denen (sagen wir) ein Objekt einen Verweis auf sich selbst übergibt, damit das aufgerufene Objekt eine im Aufrufer definierte Methode aufrufen kann. Also versuche ich es nicht zu weit zu zwingen. Ich verwende viele vollqualifizierte Namen und explizite Instanzvariablen (mit self ), bei denen ich mich in anderen Sprachen darauf verlassen kann, dass der Interpreter oder der Compiler den Bereich genauer verwaltet. Mit Klassen und statischen Methoden ist dies einfacher. Aus diesem Grund sind sie meiner Meinung nach die bessere Wahl für komplexe Pakete, bei denen Abstraktion und Verstecken von Informationen am nützlichsten sind.
quelle