`staticmethod` y` abc.abstractmethod`: ¿Se combinarán?

106

En mi aplicación Python, quiero crear un método que sea a la vez ay staticmethodan abc.abstractmethod. ¿Cómo hago esto?

Intenté aplicar ambos decoradores, pero no funciona. Si hago esto:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

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

Recibo una excepción *, y si hago esto:

class C(object):
    __metaclass__ = abc.ABCMeta

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

El método abstracto no se aplica.

¿Cómo puedo hacer un método estático abstracto?

*La excepción:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'
Ram Rachum
fuente
5
Actualice su respuesta aceptada.
Neil G

Respuestas:

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
fuente
7
Bien jugado, señor o señora :-) Te quedaste import abcarriba; así como una subclase que muestra la instanciación de A. (p. ej., class B(A):\n @staticmethod\n def test():\n print 10\n)
Dan Breslau
1
Actualicé el código para que funcione correctamente con subclases. A.test también debe tener el __isabstractmethod__atributo.
Rosh Oxymoron
3
¿Debería abstractstaticagregarse aguas arriba abc.py?
nnyby
3
abstractstaticmethod En desuso desde la versión 3.3: ahora es posible utilizar staticmethod con abstractmethod (), lo que hace que este decorador sea redundante. enlace
irakli khitarishvili
1
@iraklikhitarishvili ¡Aún así, eso no obliga a que el método de la subclase sea estático! Tienes que duplicar el decorador de método estático ... ¿No hay forma de evitarlo?
étale-cohomology
199

A partir de Python 3.3 , es posible combinar @staticmethod y @abstractmethod, por lo que ya no es necesaria ninguna de las otras sugerencias:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
gerrit
fuente
32
Tenga en cuenta que debe poner @staticmethodcomo primero, o obtendráAttributeError: attribute '__isabstractmethod__' of 'staticmethod' objects is not writable
Marco Sulla
3
Lo mismo para@property
zezollo
11
¡Sería realmente útil si esta fuera la respuesta aceptada!
Keerthana Prabhakaran
Exactamente lo que estaba buscando. ¡Gracias!
shanu khera
13

Esto lo hará:

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

Usted dice "¿Eh? Simplemente cambia el nombre de @abstractmethod", y esto es completamente correcto. Porque cualquier subclase de las anteriores tendrá que incluir el decorador @staticmethod de todos modos. No lo necesita aquí, excepto como documentación al leer el código. Una subclase debería verse así:

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

Para tener una función que le obligue a convertir este método en un método estático, tendrá que subclasificar ABCmeta para verificarlo y aplicarlo. Eso es mucho trabajo sin retorno real. (Si alguien olvida el decorador de @staticmethod, obtendrá un claro error de todos modos, simplemente no mencionará los métodos estáticos.

Entonces, de hecho, esto funciona igual de bien:

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

Actualización - Otra forma de explicarlo:

Que un método sea estático controla cómo se llama. Nunca se llama a un método abstracto. Y el método estático abstracto es, por lo tanto, un concepto bastante inútil, excepto para fines de documentación.

Lennart Regebro
fuente
4

Actualmente, esto no es posible en Python 2.X, que solo hará que el método sea abstracto o estático, pero no ambos.

En Python 3.2+, los nuevos decoradores abc.abstractclassmethody abc.abstractstaticmethodse agregaron para combinar su aplicación de ser abstracto y estático o abstracto y un método de clase.

Ver Python Issue 5867

Mella
fuente
11
Aunque es nuevo en Python 3.2, abstractclassmethody abstractstaticmethodse desaprobó rápidamente en Python 3.3, así como abstractproperty. docs.python.org/3/library/abc.html
glarrain
4
FYI: bugs.python.org/issue11610 describe la destrucción y una nueva forma de hacerlo ...
FlipMcF