`staticmethod` e` abc.abstractmethod`: eles se misturam?

106

Em meu aplicativo Python, quero fazer um método que seja ae staticmethodan abc.abstractmethod. Como eu faço isso?

Tentei aplicar os dois decoradores, mas não funcionou. Se eu fizer isso:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

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

Recebo uma exceção * e se eu fizer isso:

class C(object):
    __metaclass__ = abc.ABCMeta

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

O método abstrato não é obrigatório.

Como posso fazer um método estático abstrato?

*A exceção:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'
Ram Rachum
fonte
5
Por favor, atualize sua resposta aceita.
Neil G

Respostas:

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
fonte
7
Bem jogado, senhor ou senhora :-) Você deixou de fora import abcno topo; bem como uma subclasse que mostra a instanciação de A. (por exemplo, class B(A):\n @staticmethod\n def test():\n print 10\n)
Dan Breslau
1
Eu atualizei o código para funcionar corretamente com subclasses. A.test também deve ter o __isabstractmethod__atributo.
Rosh Oxymoron
3
Deve abstractstaticser adicionado a montante abc.py?
nnyby,
3
abstractstaticmethod Descontinuado desde a versão 3.3: agora é possível usar staticmethod com abstractmethod (), tornando este decorador redundante. link
irakli khitarishvili
1
@iraklikhitarishvili Ainda assim, isso não força o método da subclasse a ser estático! Você tem que duplicar o decorador de método estático ... Não há maneira de contornar isso?
étale-cohomology
199

A partir do Python 3.3 , é possível combinar @staticmethod e @abstractmethod, portanto, nenhuma das outras sugestões é mais necessária:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
gerrit
fonte
32
Observe que você deve colocar @staticmethodcomo primeiro, ou você obteráAttributeError: attribute '__isabstractmethod__' of 'staticmethod' objects is not writable
Marco Sulla
3
O mesmo para@property
zezollo
11
Seria muito útil se essa fosse a resposta aceita!
Keerthana Prabhakaran
Exatamente o que eu estava procurando. Obrigado!
Shanu Khera
13

Isso vai resolver:

  >>> 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

Você diz "Eh? Ele apenas renomeia @abstractmethod", e isso está completamente correto. Porque qualquer subclasse acima terá que incluir o decorador @staticmethod de qualquer maneira. Você não precisa disso aqui, exceto como documentação ao ler o código. Uma subclasse teria que ser assim:

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

Para ter uma função que o obrigaria a tornar esse método um método estático, você teria que criar a subclasse ABCmeta para verificar isso e aplicá-lo. É muito trabalho sem retorno real. (Se alguém esquecer o decorador @staticmethod, obterá um erro claro de qualquer maneira, apenas não mencionará os métodos estáticos.

Então, na verdade, isso funciona tão bem:

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

Atualização - Outra maneira de explicar:

O fato de um método ser estático controla como ele é chamado. Um método abstrato nunca é chamado. E o método estático abstrato é, portanto, um conceito bastante inútil, exceto para fins de documentação.

Lennart Regebro
fonte
4

Atualmente, isso não é possível no Python 2.X, que só forçará o método a ser abstrato ou estático, mas não ambos.

No Python 3.2+, os novos decoradores abc.abstractclassmethode abc.abstractstaticmethodforam adicionados para combinar sua aplicação de ser abstrato e estático ou abstrato e um método de classe.

Consulte Python Edição 5867

usuario
fonte
11
Embora novo no Python 3.2 abstractclassmethode abstractstaticmethodrapidamente descontinuado no Python 3.3, também abstractproperty. docs.python.org/3/library/abc.html
glarrain
4
Para sua informação: bugs.python.org/issue11610 descreve a privação e a nova maneira de fazê-lo ...
FlipMcF 01 de