oriented - Atributos abstractos en Python
python object oriented programming pdf (8)
Python 2.7
Hay un decorador @abstractproperty para esto:
from abc import ABCMeta, abstractmethod, abstractproperty
class A:
__metaclass__ = ABCMeta
def __init__(self):
# ...
pass
@abstractproperty
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
Si no se declara a
o b
en la clase derivada B
generará un TypeError
como:
TypeError
: no se puede crear una instancia de la clase abstractaB
con métodos abstractosa
Python 3.3+
De la documentation :
Obsoleto desde la versión 3.3: ahora es posible usar
property
,property.getter()
,property.setter()
yproperty.deleter()
conabstractmethod()
, lo que hace que este decorador sea redundante.
El ejemplo anterior esencialmente se convierte en:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass
@property
@abstractmethod
def a(self):
pass
@abstractmethod
def b(self):
pass
class B(A):
a = 1
def b(self):
pass
¿Cuál es la forma más corta / más elegante de implementar el siguiente código Scala con un atributo abstracto en Python?
abstract class Controller {
val path: String
}
El compilador de Scala impone una subclase de Controller
para definir "ruta". Una subclase se vería así:
class MyController extends Controller {
override val path = "/home"
}
Eche un vistazo al módulo abc (Abtract Base Class): http://docs.python.org/library/abc.html
Sin embargo, en mi opinión, la solución más simple y común es generar una excepción cuando se crea una instancia de la clase base o cuando se accede a su propiedad.
La implementación de Python3.6 podría verse así:
In [20]: class X:
...: def __init_subclass__(cls):
...: if not hasattr(cls, ''required''):
...: raise NotImplementedError
In [21]: class Y(X):
...: required =5
...:
In [22]: Y()
Out[22]: <__main__.Y at 0x7f08408c9a20>
La respuesta de Bastien Léonard menciona el módulo abstracto de la clase base y la respuesta de Brendan Abel se refiere a los atributos no implementados que generan errores. Para asegurarse de que la clase no se implemente fuera del módulo, puede ponerle un prefijo al subrayado que lo denota como privado para el módulo (es decir, no se importa).
es decir
class _Controller(object):
path = '''' # There are better ways to declare attributes - see other answers
class MyController(_Controller):
path = ''/Home''
Puede crear un atributo en la clase base abstracta abc.ABC con un valor como NotImplemented
para que, si el atributo no se invalide y luego se use, se muestre un error en tiempo de ejecución.
El siguiente código utiliza una sugerencia de tipo PEP 484 para ayudar a PyCharm a analizar de forma estática de forma correcta también el tipo de atributo de path
.
import abc
class Controller(abc.ABC):
path = NotImplemented # type: str
class MyController(Controller):
path = ''/home''
Python tiene una excepción incorporada para esto, aunque no encontrará la excepción hasta el tiempo de ejecución.
class Base(object):
@property
def path(self):
raise NotImplementedError
class SubClass(Base):
path = ''blah''
Su clase base podría implementar un método __new__
que verifique el atributo de clase:
class Controller(object):
def __new__(cls, *args, **kargs):
if not hasattr(cls,''path''):
raise NotImplementedError("''Controller'' subclasses should have a ''path'' attribute")
return object.__new__(cls,*args,**kargs)
class C1(Controller):
path = 42
class C2(Controller):
pass
c1 = C1()
# ok
c2 = C2()
# NotImplementedError: ''Controller'' subclasses should have a ''path'' attribute
De esta forma, el error aumenta en instanciación
class AbstractStuff:
@property
@abc.abstractmethod
def some_property(self):
pass
A partir de 3.3 abc.abstractproperty
está en desuso, creo.