Como se explica en las otras respuestas, sí, puede usar clases abstractas en Python usando el abc
módulo . A continuación voy a dar un ejemplo real utilizando abstracta @classmethod
, @property
y @abstractmethod
(usando Python 3.6 o superior). Para mí, generalmente es más fácil comenzar con ejemplos que puedo copiar y pegar fácilmente; Espero que esta respuesta también sea útil para otros.
Primero creemos una clase base llamada Base
:
from abc import ABC, abstractmethod
class Base(ABC):
@classmethod
@abstractmethod
def from_dict(cls, d):
pass
@property
@abstractmethod
def prop1(self):
pass
@property
@abstractmethod
def prop2(self):
pass
@prop2.setter
@abstractmethod
def prop2(self, val):
pass
@abstractmethod
def do_stuff(self):
pass
Nuestra Base
clase siempre tendrá unfrom_dict
classmethod
, a property
prop1
(que es de solo lectura) y a property
prop2
(que también se puede configurar), así como una función llamada do_stuff
. Cualquier clase en la que se cree ahora Base
tendrá que implementar todo esto para métodos / propiedades. Tenga en cuenta que para que un método sea abstracto, se requieren dos decoradores, classmethod
y abstracto property
.
Ahora podríamos crear una clase A
como esta:
class A(Base):
def __init__(self, name, val1, val2):
self.name = name
self.__val1 = val1
self._val2 = val2
@classmethod
def from_dict(cls, d):
name = d['name']
val1 = d['val1']
val2 = d['val2']
return cls(name, val1, val2)
@property
def prop1(self):
return self.__val1
@property
def prop2(self):
return self._val2
@prop2.setter
def prop2(self, value):
self._val2 = value
def do_stuff(self):
print('juhu!')
def i_am_not_abstract(self):
print('I can be customized')
Todos los métodos / propiedades requeridos se implementan y, por supuesto, también podemos agregar funciones adicionales que no son parte de Base
(aquí:) i_am_not_abstract
.
Ahora podemos hacer:
a1 = A('dummy', 10, 'stuff')
a2 = A.from_dict({'name': 'from_d', 'val1': 20, 'val2': 'stuff'})
a1.prop1
# prints 10
a1.prop2
# prints 'stuff'
Como lo deseamos, no podemos establecer prop1
:
a.prop1 = 100
volverá
AttributeError: no se puede establecer el atributo
También nuestro from_dict
método funciona bien:
a2.prop1
# prints 20
Si ahora definimos una segunda clase B
como esta:
class B(Base):
def __init__(self, name):
self.name = name
@property
def prop1(self):
return self.name
e intenté instanciar un objeto como este:
b = B('iwillfail')
obtendremos un error
TypeError: no se puede crear una instancia de la clase abstracta B con métodos abstractos do_stuff, from_dict, prop2
enumerando todas las cosas definidas en las Base
que no implementamos B
.