"abc" --- Classes Base Abstratas
********************************

**Código-fonte:** Lib/abc.py

======================================================================

Este módulo fornece a infraestrutura para definir *abstract base
classes* (CBAs) 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 "ABCMeta" como sua metaclasse. Com essa
   classe, uma classe base abstrata pode ser criada simplesmente
   derivando da "ABC" evitando às vezes confundir o uso da metaclasse,
   por exemplo:

      from abc import ABC

      class MyABC(ABC):
          pass

   Note que o tipo da classe "ABC" ainda é "ABCMeta", portanto herdar
   da "ABC" requer 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 usar "ABCMeta" diretamente,
   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 via "super()"). [1]

   Classes criadas com a metaclasse de "ABCMeta" tem 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ção "get_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 "issubclass" sem a necessidade de chamar
      "register()" 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", "False" ou "NotImplemented".
      Se retornar "True", a *subclasse* é considerada uma subclasse
      desta CBA. Se retornar "False", a *subclasse* não é considerada
      uma subclasse desta CBA, mesmo que normalmente seria uma. Se
      retornar "NotImplemented", 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 "Mylterable" da 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étodo "get_iterator()" é
   também parte da classe base abstrata "MyIterable" , 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 uma "MyIterable" também.

   Finalmente, a última linha faz de "Foo" uma subclasse virtual da
   "MyIterable", 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á o "get_iterator"
   disponível como um método de "Foo", 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
   "ABCMeta" ou seja derivada desta. Uma classe que tem uma metaclasse
   derivada de "ABCMeta" nã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 CBA "register()" 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 ser "True" se
   algum dos métodos usados para compor o descritor for abstrato. Por
   exemplo, a "property" embutida 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 "classmethod"
   com "abstractmethod()", 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 "staticmethod"
   com "abstractmethod()", 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()" e "property.deleter()" com
   "abstractmethod()", 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++.
