Como explicado em outras respostas, sim, você pode usar classes abstratas em Python utilizando o abc
módulo . Abaixo eu dar um exemplo real usando abstrato @classmethod
, @property
e @abstractmethod
(usando Python 3.6+). Para mim, geralmente é mais fácil começar com exemplos que eu posso copiar e colar facilmente; Espero que esta resposta também seja útil para outros.
Vamos primeiro criar uma classe base chamada 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
Nossa Base
classe sempre terá a from_dict
classmethod
, a property
prop1
(que é somente leitura) e a property
prop2
(que também podem ser configuradas), bem como uma função chamada do_stuff
. Qualquer que seja a classe criada agora Base
, terá que implementar tudo isso para métodos / propriedades. Observe que, para um método ser abstrato, são necessários dois decoradores - classmethod
e abstrato property
.
Agora poderíamos criar uma classe 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 os métodos / propriedades necessários são implementados e podemos - é claro - também adicionar funções adicionais que não fazem parte Base
(aqui i_am_not_abstract
:).
Agora podemos fazer:
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 desejado, não podemos definir prop1
:
a.prop1 = 100
retornará
AttributeError: não é possível definir o atributo
Também nosso from_dict
método funciona bem:
a2.prop1
# prints 20
Se agora definimos uma segunda classe B
como esta:
class B(Base):
def __init__(self, name):
self.name = name
@property
def prop1(self):
return self.name
e tentou instanciar um objeto como este:
b = B('iwillfail')
receberemos um erro
TypeError: Não é possível instanciar a classe abstrata B com métodos abstratos do_stuff, from_dict, prop2
listando todas as coisas definidas nas Base
quais não implementamos B
.