`staticmethod` et` abc.abstractmethod`: va-t-il se mélanger?

106

Dans mon application Python, je souhaite créer une méthode à la fois un staticmethodet un abc.abstractmethod. Comment puis-je faire cela?

J'ai essayé d'appliquer les deux décorateurs, mais cela ne fonctionne pas. Si je fais ceci:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    @staticmethod    
    def my_function(): pass

J'obtiens une exception *, et si je fais ceci:

class C(object):
    __metaclass__ = abc.ABCMeta

    @staticmethod    
    @abc.abstractmethod
    def my_function(): pass

La méthode abstraite n'est pas appliquée.

Comment puis-je créer une méthode statique abstraite?

*L'éxéption:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'
Ram Rachum
la source
5
Veuillez mettre à jour votre réponse acceptée.
Neil G

Réponses:

34
class abstractstatic(staticmethod):
    __slots__ = ()
    def __init__(self, function):
        super(abstractstatic, self).__init__(function)
        function.__isabstractmethod__ = True
    __isabstractmethod__ = True

class A(object):
    __metaclass__ = abc.ABCMeta
    @abstractstatic
    def test():
        print 5
Rosh Oxymoron
la source
7
Bien joué, monsieur ou madame :-) Vous avez laissé en import abchaut; ainsi qu'une sous-classe qui montre l'instanciation de A. (par exemple, class B(A):\n @staticmethod\n def test():\n print 10\n)
Dan Breslau
1
J'ai mis à jour le code pour qu'il fonctionne correctement avec le sous-classement. A.test doit également avoir l' __isabstractmethod__attribut.
Rosh Oxymoron
3
Doit abstractstaticêtre ajouté en amont à abc.py?
nnyby
3
abstractstaticmethod Déconseillé depuis la version 3.3: Il est désormais possible d'utiliser staticmethod avec abstractmethod (), ce qui rend ce décorateur redondant. link
irakli khitarishvili
1
@iraklikhitarishvili Pourtant, cela n'impose pas que la méthode de la sous-classe soit statique! Vous devez dupliquer le décorateur de méthode statique ... N'y a-t-il pas moyen de contourner cela?
étale-cohomology
199

À partir de Python 3.3 , il est possible de combiner @staticmethod et @abstractmethoddonc aucune des autres suggestions n'est plus nécessaire:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
gerrit
la source
32
Notez que vous devez mettre @staticmethoden premier, ou vous obtiendrezAttributeError: attribute '__isabstractmethod__' of 'staticmethod' objects is not writable
Marco Sulla
3
Idem pour@property
zezollo
11
Ce serait vraiment utile si c'était la réponse acceptée!
Keerthana Prabhakaran
Exactement ce que je cherchais. Merci!
shanu khera le
13

Cela le fera:

  >>> import abc
  >>> abstractstaticmethod = abc.abstractmethod
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abstractstaticmethod
  ...     def themethod():
  ...          pass
  ... 
  >>> a = A()
  >>> Traceback (most recent call last):
  File "asm.py", line 16, in <module>
    a = A()
  TypeError: Can't instantiate abstract class A with abstract methods test

Vous dites "Hein? Il renomme simplement @abstractmethod", et c'est tout à fait correct. Parce que toute sous-classe de ce qui précède devra de toute façon inclure le décorateur @staticmethod. Vous n'en avez pas besoin ici, sauf comme documentation lors de la lecture du code. Une sous-classe devrait ressembler à ceci:

  >>> class B(A):
  ...     @staticmethod
  ...     def themethod():
  ...         print "Do whatevs"

Pour avoir une fonction qui vous obligerait à faire de cette méthode une méthode statique, vous devez sous-classer ABCmeta pour vérifier cela et l'appliquer. C'est beaucoup de travail sans retour réel. (Si quelqu'un oublie le décorateur @staticmethod, il obtiendra de toute façon une erreur claire, cela ne mentionnera tout simplement pas les méthodes statiques.

Donc, en fait, cela fonctionne aussi bien:

  >>> import abc
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abc.abstractmethod
  ...     def themethod():
  ...         """Subclasses must implement this as a @staticmethod"""
  ...          pass

Mise à jour - Une autre façon de l'expliquer:

Le fait qu'une méthode soit statique contrôle la façon dont elle est appelée. Une méthode abstraite n'est jamais appelée. Et la méthode statique abstraite est donc un concept assez inutile, sauf à des fins de documentation.

Lennart Regebro
la source
4

Ce n'est actuellement pas possible dans Python 2.X, qui imposera uniquement à la méthode d'être abstraite ou statique, mais pas les deux.

Dans Python 3.2+, les nouveaux décorateurs abc.abstractclassmethodet abc.abstractstaticmethodont été ajoutés pour combiner leur application d'être abstrait et statique ou abstrait et une méthode de classe.

Voir le problème Python 5867

pseudo
la source
11
Bien que nouveau dans Python 3.2, abstractclassmethodet abstractstaticmethodrapidement obsolète dans Python 3.3, ainsi que abstractproperty. docs.python.org/3/library/abc.html
glarrain
4
FYI: bugs.python.org/issue11610 décrit la dépréciation et une nouvelle façon de le faire ...
FlipMcF