Lorsque j'essaie d'utiliser une méthode statique à partir du corps de la classe et que je définis la méthode statique en utilisant la staticmethod
fonction intégrée en tant que décorateur, comme ceci:
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
J'obtiens l'erreur suivante:
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
Je comprends pourquoi cela se produit (liaison de descripteur) , et je peux le contourner en convertissant manuellement _stat_func()
en une méthode statique après sa dernière utilisation, comme ceci:
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
Ma question est donc:
Y a-t-il de meilleures façons, par exemple, plus propres ou plus «pythoniques», d'accomplir cela?
python
decorator
static-methods
Martineau
la source
la source
staticmethod
du tout. Ils sont généralement plus utiles en tant que fonctions au niveau du module, auquel cas votre problème n'est pas un problème.classmethod
, d'autre part ...Réponses:
staticmethod
les objets ont apparemment un__func__
attribut stockant la fonction brute d'origine (il est logique qu'ils le fassent). Donc cela fonctionnera:En passant, même si je soupçonnais qu'un objet staticmethod avait une sorte d'attribut stockant la fonction d'origine, je n'avais aucune idée des détails. Dans l'esprit d'apprendre à quelqu'un à pêcher plutôt que de lui donner un poisson, voici ce que j'ai fait pour enquêter et le découvrir (un C&P de ma session Python):
Des types similaires de fouille dans une session interactive (
dir
est très utile) peuvent souvent résoudre ce type de questions très rapidement.la source
__func__
n'est qu'un autre nomim_func
et a été ajouté à Py 2.6 pour la compatibilité ascendante Python 3.__func__
attribut d'une méthode statique vous donne une référence à la fonction d'origine, exactement comme si vous n'aviez jamais utilisé lestaticmethod
décorateur. Donc, si votre fonction nécessite des arguments, vous devrez les passer lors de l'appel__func__
. Le message d'erreur qui vous semble tout à fait semble que vous ne lui avez donné aucun argument. Si l'exemplestat_func
de cet article prenait deux arguments, vous utiliseriez_ANS = stat_func.__func__(arg1, arg2)
stat_func
elle-même est une telle variable). Vouliez-vous dire que vous ne pouvez pas utiliser les attributs d'instance de la classe que vous définissez? C'est vrai, mais sans surprise; nous n'avons une instance de la classe, puisque nous définissons toujours la classe! Mais de toute façon, je les entendais simplement comme des supports pour tous les arguments que vous vouliez faire passer; vous pouvez y utiliser des littéraux.C'est comme ça que je préfère:
Je préfère cette solution à
Klass.stat_func
, en raison du principe DRY . Cela me rappelle la raison pour laquelle il y a un nouveausuper()
dans Python 3 :)Mais je suis d'accord avec les autres, généralement le meilleur choix est de définir une fonction au niveau du module.
Par exemple, avec la
@staticmethod
fonction, la récursivité peut ne pas sembler très bonne (vous auriez besoin de casser le principe DRY en appelantKlass.stat_func
à l' intérieurKlass.stat_func
). C'est parce que vous n'avez pas de référence àself
la méthode statique interne. Avec la fonction de niveau de module, tout semblera OK.la source
self.__class__.stat_func()
de méthodes régulières présente des avantages (DRY et tout ça) par rapport à l'utilisationKlass.stat_func()
, ce n'était pas vraiment le sujet de ma question - en fait, j'ai évité d'utiliser la première pour ne pas brouiller le problème de l'incohérence.self.__class__
est mieux car si une sous-classe remplacestat_func
, alorsSubclass.method
appellera la sous-classestat_func
. Mais pour être tout à fait honnête, dans cette situation, il est préférable d'utiliser simplement une méthode réelle au lieu d'une méthode statique.Qu'en est-il de l'injection de l'attribut de classe après la définition de classe?
la source
Cela est dû au fait que staticmethod est un descripteur et nécessite une extraction d'attribut au niveau de la classe pour exercer le protocole du descripteur et obtenir le vrai appelable.
À partir du code source:
Mais pas directement de l'intérieur de la classe pendant sa définition.
Mais comme un commentateur l'a mentionné, ce n'est pas du tout une conception "pythonique". Utilisez simplement une fonction de niveau module à la place.
la source
Et cette solution? Il ne repose pas sur la connaissance de la
@staticmethod
mise en œuvre du décorateur. La classe interne StaticMethod joue comme un conteneur de fonctions d'initialisation statiques.la source
__func__
car elle est maintenant officiellement documentée (voir la section Autres changements de langage des nouveautés de Python 2.7 et sa référence au numéro 5982 ). Votre solution est encore plus portable, car elle fonctionnerait probablement aussi dans les versions Python antérieures à 2.6 (quand a__func__
été introduite pour la première fois comme synonyme deim_func
).