Wenn ich versuche, eine statische Methode aus dem Hauptteil der Klasse heraus zu verwenden und die statische Methode mithilfe der integrierten staticmethod
Funktion als Dekorator wie folgt zu definieren:
class Klass(object):
@staticmethod # use as decorator
def _stat_func():
return 42
_ANS = _stat_func() # call the staticmethod
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
Ich erhalte folgende Fehlermeldung:
Traceback (most recent call last):<br>
File "call_staticmethod.py", line 1, in <module>
class Klass(object):
File "call_staticmethod.py", line 7, in Klass
_ANS = _stat_func()
TypeError: 'staticmethod' object is not callable
Ich verstehe, warum dies geschieht (Deskriptorbindung) , und kann es _stat_func()
umgehen, indem ich es nach seiner letzten Verwendung manuell in eine statische Methode konvertiere , wie folgt:
class Klass(object):
def _stat_func():
return 42
_ANS = _stat_func() # use the non-staticmethod version
_stat_func = staticmethod(_stat_func) # convert function to a static method
def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret
Meine Frage lautet also:
Gibt es bessere Möglichkeiten, dies zu erreichen, wie bei saubereren oder "pythonischeren"?
python
decorator
static-methods
Martineau
quelle
quelle
staticmethod
. Sie sind normalerweise als Funktionen auf Modulebene nützlicher. In diesem Fall ist Ihr Problem kein Problem.classmethod
, auf der anderen Seite ...Antworten:
staticmethod
Objekte haben anscheinend ein__func__
Attribut, das die ursprüngliche Rohfunktion speichert (macht Sinn, dass sie es mussten). Das wird also funktionieren:Abgesehen davon hatte ich keine Ahnung von den Einzelheiten, obwohl ich vermutete, dass ein statisches Methodenobjekt eine Art Attribut hatte, in dem die ursprüngliche Funktion gespeichert war. Um jemandem das Fischen beizubringen, anstatt ihm einen Fisch zu geben, habe ich Folgendes getan, um dies zu untersuchen und herauszufinden (ein C & P aus meiner Python-Sitzung):
Ähnliche Arten des Grabens in einer interaktiven Sitzung (
dir
ist sehr hilfreich) können diese Art von Fragen oft sehr schnell lösen.quelle
__func__
nur ein anderer Name für istim_func
und Py 2.6 für Python 3-Vorwärtskompatibilität hinzugefügt wurde.__func__
Attribut einer statischen Methode erhalten Sie einen Verweis auf die ursprüngliche Funktion, genau so, als hätten Sie denstaticmethod
Dekorator noch nie verwendet . Wenn Ihre Funktion Argumente erfordert, müssen Sie diese beim Aufruf übergeben__func__
. Die Fehlermeldung, die Sie ganz klingen, als hätten Sie ihr keine Argumente gegeben. Wenn dasstat_func
in diesem Beitrag Beispiel zwei Argumente nehmen würde, würden Sie verwenden_ANS = stat_func.__func__(arg1, arg2)
stat_func
selbst ist eine solche Variable). Meinten Sie, Sie können keine Instanzattribute der von Ihnen definierten Klasse verwenden? Das ist wahr, aber nicht überraschend; wir nicht haben eine Instanz der Klasse, da wir die Klasse immer noch sind zu definieren! Aber trotzdem habe ich sie nur als Ersatz für die Argumente gemeint, die Sie vorbringen wollten. Sie könnten dort Literale verwenden.So bevorzuge ich:
Ich bevorzuge diese Lösung
Klass.stat_func
wegen des DRY-Prinzips . Erinnert mich an den Grund, warum essuper()
in Python 3 eine neue gibt :)Aber ich stimme den anderen zu. Normalerweise ist es die beste Wahl, eine Funktion auf Modulebene zu definieren.
Zum Beispiel mit
@staticmethod
Funktion sieht die Rekursion möglicherweise nicht sehr gut aus (Sie müssten das DRY-Prinzip brechen, indem SieKlass.stat_func
inside aufrufenKlass.stat_func
). Das liegt daran, dass Sie keinen Verweis auf dieself
statische Methode haben. Mit der Funktion auf Modulebene sieht alles in Ordnung aus.quelle
self.__class__.stat_func()
in regulären Methoden Vorteile (DRY und all das) gegenüber der Verwendung hatKlass.stat_func()
, aber das war nicht wirklich das Thema meiner Frage - tatsächlich habe ich die Verwendung der ersteren vermieden, um das Problem der Inkonsistenz nicht zu trüben.self.__class__
ist besser, denn wenn eine Unterklasse überschreibtstat_func
,Subclass.method
werden die Unterklassen aufgerufenstat_func
. Aber um ganz ehrlich zu sein, ist es in dieser Situation viel besser, nur eine echte Methode anstelle einer statischen zu verwenden.Was ist mit dem Einfügen des Klassenattributs nach der Klassendefinition?
quelle
Dies liegt daran, dass staticmethod ein Deskriptor ist und ein Attributabruf auf Klassenebene erforderlich ist, um das Deskriptorprotokoll auszuüben und den wahren Aufruf zu erhalten.
Aus dem Quellcode:
Aber nicht direkt aus der Klasse heraus, während sie definiert wird.
Aber wie ein Kommentator erwähnte, ist dies überhaupt kein "Pythonic" -Design. Verwenden Sie stattdessen einfach eine Funktion auf Modulebene.
quelle
Was ist mit dieser Lösung? Es beruht nicht auf Kenntnissen über die
@staticmethod
Implementierung des Dekorateurs. Die innere Klasse StaticMethod wird als Container für statische Initialisierungsfunktionen abgespielt.quelle
__func__
da es jetzt offiziell dokumentiert ist (siehe Abschnitt Andere Sprachänderungen der Neuerungen in Python 2.7 und den Verweis auf Ausgabe 5982 ). Ihre Lösung ist noch portabler, da sie wahrscheinlich auch in Python-Versionen vor Version 2.6 funktionieren würde (als sie__func__
erstmals als Synonym für eingeführt wurdeim_func
).