50 votes

Décorateur Python comme méthode statique

J'essaie d'écrire une classe python qui utilise une fonction de décorateur qui a besoin d'informations sur l'état de l'instance. Cela fonctionne comme prévu, mais si je fais explicitement du décorateur un staticmetod, j'obtiens l'erreur suivante:

 Traceback (most recent call last):
  File "tford.py", line 1, in <module>
    class TFord(object):
  File "tford.py", line 14, in TFord
    @ensure_black
TypeError: 'staticmethod' object is not callable
 

Pourquoi?

Voici le code:

 class TFord(object):
    def __init__(self, color):
        self.color = color

    @staticmethod
    def ensure_black(func):
        def _aux(self, *args, **kwargs):
            if self.color == 'black':
                return func(*args, **kwargs)
            else:
                return None
        return _aux

    @ensure_black
    def get():
        return 'Here is your shiny new T-Ford'

if __name__ == '__main__':
    ford_red = TFord('red')
    ford_black = TFord('black')

    print ford_red.get()
    print ford_black.get()
 

Et si je supprime simplement la ligne @staticmethod , tout fonctionne, mais je ne comprends pas pourquoi. Ne devrait-il pas avoir besoin de self comme premier argument?

45voto

Sven Marnach Points 133943

Ce n'est pas la façon dont staticmethod est censé être utilisé. Un staticmethod objet utilise des descripteurs de retourner l'objet enveloppé, de sorte qu'il ne fonctionne que lors de l'accès en tant que classname.staticmethodname. Exemple

class A(object):
    @staticmethod
    def f():
        pass
print A.f
print A.__dict__["f"]

imprime

<function f at 0x8af45dc>
<staticmethod object at 0x8aa6a94>

À l'intérieur de la portée de l' A, vous obtenez toujours le dernier objet, qui n'est pas appelable.

Je recommanderais fortement à déplacer le dcorator à la portée de module -- il ne semble pas appartenir à l'intérieur de la classe. Si vous voulez le garder à l'intérieur de la classe, ne pas en faire un staticmethod, mais plutôt de simplement del à la fin du corps de la classe -- il n'est pas destiné à être utilisé à partir de l'extérieur de la classe dans ce cas.

9voto

jfocht Points 704

Les classes Python sont créés lors de l'exécution, après avoir évalué le contenu de la déclaration de classe. La classe est évaluée par assigné toutes les variables déclarées et les fonctions de spécial à un dictionnaire et à l'aide de ce dictionnaire à l'appel type.__new__ (voir personnalisation de la création de classes).

Donc,

class A(B):
    c = 1

est équivalent à:

A = type.__new__("A", (B,), {"c": 1})

Lorsque vous annotez une méthode avec @staticmethod, il y a quelque chose de magique qui se passe APRÈS la classe est créée avec type.__new__. À l'intérieur de la déclaration de classe de la portée, l' @staticmethod la fonction est une instance d'une staticmethod objet, vous ne pouvez pas appeler. Le décorateur doit probablement juste être déclarées ci-dessus la définition de la classe dans le même module OU dans un autre "décorer" le module (dépend du nombre de décorateurs vous avez). En général, les décorateurs doivent être déclarées à l'extérieur d'une classe. Une exception notable est la propriété de la classe (voir propriétés). Dans votre cas, avoir le décorateur à l'intérieur d'une déclaration de classe peut faire sens que si on avait quelque chose comme une classe de couleur:

class Color(object):

    def ___init__(self, color):
        self.color = color

     def ensure_same_color(f):
         ...

black = Color("black")

class TFord(object):
    def __init__(self, color):
        self.color = color

    @black.ensure_same_color
    def get():
        return 'Here is your shiny new T-Ford'

-1voto

Felipe Cruz Points 628

ensure_black renvoie une méthode _aux qui n'est pas décorée par @staticmethod

Vous pouvez renvoyer une méthode non statique à un static_method

http://docs.python.org/library/functions.html#staticmethod

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X