211 votes

Appeler une méthode statique de classe dans le corps de la classe ?

Lorsque je tente d'utiliser une méthode statique à partir du corps de la classe, et que je définis la méthode statique à l'aide de la fonction intégrée staticmethod comme un 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

Je reçois l'erreur suivante :

Traceback (most recent call last):
  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 des descripteurs). et vous pouvez 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

Donc ma question est :

     Existe-t-il des moyens plus propres ou plus "pythoniques" d'accomplir cette tâche ?

2voto

Alechan Points 106

Si le "problème central" est l'assignation de variables de classe à l'aide de fonctions, une alternative est d'utiliser une métaclasse (c'est un peu "ennuyeux" et "magique" et je suis d'accord que la méthode statique devrait être appelable à l'intérieur de la classe, mais malheureusement ce n'est pas le cas). De cette façon, nous pouvons refactoriser le comportement en une fonction autonome et ne pas encombrer la classe.

class KlassMetaClass(type(object)):
    @staticmethod
    def _stat_func():
        return 42

    def __new__(cls, clsname, bases, attrs):
        # Call the __new__ method from the Object metaclass
        super_new = super().__new__(cls, clsname, bases, attrs)
        # Modify class variable "_ANS"
        super_new._ANS = cls._stat_func()
        return super_new

class Klass(object, metaclass=KlassMetaClass):
    """
    Class that will have class variables set pseudo-dynamically by the metaclass
    """
    pass

print(Klass._ANS) # prints 42

L'utilisation de cette alternative "dans le monde réel" peut être problématique. J'ai dû l'utiliser pour remplacer des variables de classe dans des classes Django, mais dans d'autres circonstances, il est peut-être préférable d'opter pour l'une des solutions proposées dans les autres réponses.

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