abc — Classes Base Abstratas¶
Código-fonte: Lib/abc.py
Este módulo fornece a infraestrutura para definir classes base abstratas (CBAs. Sigla em inglês ABC, de abstract base class) em Python, como delineado em PEP 3119; veja o PEP para entender o porquê isto foi adicionado ao Python. (Veja também PEP 3141 e o módulo numbers sobre uma hierarquia de tipo para números baseado nas CBAs.)
O módulo collections tem algumas classes concretas que derivam de CBAs; essas podem, evidentemente, ser ainda mais derivadas. Além disso, o submódulo collections.abc tem algumas CBAs que podem ser usadas para testar se uma classe ou instância oferece uma interface particular, por exemplo, se é hasheável ou se é um mapeamento.
Este módulo fornece a metaclasse ABCMeta para definir CBAs e uma classe auxiliar ABC para alternativamente definir CBAs através de herança:
-
class
abc.ABC¶ Uma classe auxiliar que tem
ABCMetacomo sua metaclasse. Com essa classe, uma classe base abstrata pode ser criada simplesmente derivando daABCevitando às vezes confundir o uso da metaclasse, por exemplo:from abc import ABC class MyABC(ABC): pass
Note que o tipo da classe
ABCainda éABCMeta, portanto herdar daABCrequer as precauções usuais a respeito do uso da metaclasse, pois herança múltipla pode levar a conflitos de metaclasse. Pode-se também definir uma classe base abstrata ao passar a palavra reservada metaclasse e usarABCMetadiretamente, por exemplo:from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
Novo na versão 3.4.
-
class
abc.ABCMeta¶ Metaclasse para definir Classe Base Abstrata (CBAs).
Use esta metaclasse para criar uma CBA. Uma CBA pode ser diretamente subclasseada, e então agir como uma classe misturada. Você também pode registrar classes concretas não relacionadas (até mesmo classes embutidas) e CBAs não relacionadas como “subclasses virtuais” – estas e suas descendentes serão consideradas subclasses da CBA de registro pela função embutida
issubclass(), mas a CBA de registro não irá aparecer na ORM (Ordem de Resolução do Método) e nem as implementações do método definidas pela CBA de registro será chamável (nem mesmo viasuper()). 1Classes criadas com a metaclasse de
ABCMetatem o seguinte método:-
register(subclass)¶ Registrar subclasse como uma “subclasse virtual” desta CBA. Por exemplo:
from abc import ABC class MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
Alterado na versão 3.3: Retorna a subclasse registrada, para permitir o uso como um decorador de classe.
Alterado na versão 3.4: Para detectar chamadas para
register(), você pode usar a funçãoget_cache_token().
Você também pode sobrepor este método em uma classe base abstrata:
-
__subclasshook__(subclass)¶ (Deve obrigatoriamente ser definido como um método de classe.)
Cheque se a subclasse é considerada uma subclasse desta CBA. Isto significa que você pode customizar ainda mais o comportamento da
issubclasssem a necessidade de chamarregister()em toda classe que você queira considerar uma subclasse da CBA. (Este método de classe é chamado do método da CBA__subclasscheck__().)Este método deve retornar
True,FalseouNotImplemented. Se retornarTrue, a subclasse é considerada uma subclasse desta CBA. Se retornarFalse, a subclasse não é considerada uma subclasse desta CBA, mesmo que normalmente seria uma. Se retornarNotImplemented, a verificação da subclasse é continuada com o mecanismo usual.
Para uma demonstração destes conceitos, veja este exemplo de definição CBA:
class Foo: def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable(ABC): @abstractmethod def __iter__(self): while False: yield None def get_iterator(self): return self.__iter__() @classmethod def __subclasshook__(cls, C): if cls is MyIterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented MyIterable.register(Foo)
A
Mylterableda CBA define o método iterável padrão,__iter__(), como um método abstrato. A implementação dada aqui pode ainda ser chamada da subclasse. O métodoget_iterator()é também parte da classe base abstrataMyIterable, mas não precisa ser substituído nas classes derivadas não abstratas.O método de classe
__subclasshook__()definido aqui diz que qualquer classe que tenha um método__iter__()em seu__dict__(ou no de uma de suas classes base, acessados via lista__mro__) é considerada umaMyIterabletambém.Finalmente, a última linha faz de
Foouma subclasse virtual daMyIterable, apesar de não definir um método__iter__()(ela usa o protocolo iterável antigo, definido em termos de__len__()e__getitem__()). Note que isto não fará oget_iteratordisponível como um método deFoo, então ele é fornecido separadamente.-
O módulo abc também fornece o seguinte decorador:
-
@abc.abstractmethod¶ Um decorador indicando métodos abstratos.
Usar este decorador requer que a metaclasse da classe seja
ABCMetaou seja derivada desta. Uma classe que tem uma metaclasse derivada deABCMetanão pode ser instanciada, a menos que todos os seus métodos abstratos e propriedades estejam substituídos. Os métodos abstratos podem ser chamados usando qualquer um dos mecanismos normais de ‘super’ chamadas.abstractmethod()pode ser usado para declarar métodos abstratos para propriedades e descritores.Adicionar dinamicamente métodos abstratos a uma classe, ou tentar modificar o status de abstração de um método ou classe uma vez que estejam criados, não é tolerado. A
abstractmethod()afeta apenas subclasses derivadas usando herança regular; “subclasses virtuais” registradas com o método da CBAregister()não são afetadas.Quando
abstractmethod()é aplicado em combinação com outros descritores de método, ele deve ser aplicado como o decorador mais interno, como mostrado nos seguintes exemplos de uso:class C(ABC): @abstractmethod def my_abstract_method(self, ...): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ... @staticmethod @abstractmethod def my_abstract_staticmethod(...): ... @property @abstractmethod def my_abstract_property(self): ... @my_abstract_property.setter @abstractmethod def my_abstract_property(self, val): ... @abstractmethod def _get_x(self): ... @abstractmethod def _set_x(self, val): ... x = property(_get_x, _set_x)
Para que interopere corretamente com o maquinário da classe base abstrata, o descritor precisa identificar-se como abstrato usando
__isabstractmethod__. No geral, este atributo deve serTruese algum dos métodos usados para compor o descritor for abstrato. Por exemplo, apropertyembutida do Python faz o equivalente a:class Descriptor: ... @property def __isabstractmethod__(self): return any(getattr(f, '__isabstractmethod__', False) for f in (self._fget, self._fset, self._fdel))
Nota
Diferente de métodos abstratos Java, esses métodos abstratos podem ter uma implementação. Esta implementação pode ser chamada via mecanismo da
super()da classe que a substitui. Isto pode ser útil como um ponto final para uma super chamada em um framework que usa herança múltipla cooperativa.
O módulo abc também suporta os seguintes decoradores herdados:
-
@abc.abstractclassmethod¶ Novo na versão 3.2.
Obsoleto desde a versão 3.3: Agora é possível usar
classmethodcomabstractmethod(), tornando redundante este decorador.Uma subclasse da
classmethod()embutida, indicando um método de classe abstrato. Caso contrário, é similar àabstractmethod().Este caso especial está descontinuado, pois o decorador da
classmethod()está agora corretamente identificado como abstrato quando aplicado a um método abstrato:class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ...
-
@abc.abstractstaticmethod¶ Novo na versão 3.2.
Obsoleto desde a versão 3.3: Agora é possível usar
staticmethodcomabstractmethod(), tornando redundante este decorador.Uma subclasse da
staticmethod()embutida, indicando um método estático abstrato. Caso contrário, ela é similar àabstractmethod().Este caso especial está descontinuado, pois o decorador da
staticmethod()está agora corretamente identificado como abstrato quando aplicado a um método abstrato:class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(...): ...
-
@abc.abstractproperty¶ Obsoleto desde a versão 3.3: Agora é possível usar
property,property.getter(),property.setter()eproperty.deleter()comabstractmethod(), tornando redundante este decorador.Uma subclasse da
property()embutida, indicando uma propriedade abstrata.Este caso especial está descontinuado, pois o decorador da
property()está agora corretamente identificado como abstrato quando aplicado a um método abstrato:class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
O exemplo acima define uma propriedade somente leitura; você também pode definir uma propriedade abstrata de leitura e escrita marcando apropriadamente um ou mais dos métodos subjacentes como abstratos:
class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...
Se apenas alguns componentes são abstratos, apenas estes componentes precisam ser atualizados para criar uma propriedade concreta em uma subclasse:
class D(C): @C.x.setter def x(self, val): ...
O módulo abc também fornece as seguintes funções:
-
abc.get_cache_token()¶ Retorna o token de cache da classe base abstrata atual.
O token é um objeto opaco (que suporta teste de igualdade) identificando a versão atual do cache da classe base abstrata para subclasses virtuais. O token muda a cada chamada ao
ABCMeta.register()em qualquer CBA.Novo na versão 3.4.
Notas de rodapé
- 1
Programadores C++ devem notar que o conceito da classe base virtual do Python não é o mesmo que o de C++.