Pular para o conteúdo

    Capítulo 30, Intermediário

    Abstração com ABC

    Uma classe abstrata define um contrato que as filhas são obrigadas a cumprir. É o jeito de dizer "qualquer classe que faça X precisa ter estes métodos".

    Código deste capítulo: intermediario/cap30_abstracao.py

    O contrato

    O módulo abc oferece ABC e @abstractmethod. Uma classe com métodos abstratos não pode ser instanciada. As subclasses precisam implementar todos eles:

    intermediario/cap30_abstracao.pylinhas 10 a 40
    from abc import ABC, abstractmethod
    import math
    
    
    class Forma(ABC):
        @abstractmethod
        def area(self):
            ...
    
        def descrever(self):
            return f"{type(self).__name__} com área {self.area():.2f}"
    
    
    class Circulo(Forma):
        def __init__(self, raio):
            self.raio = raio
    
        def area(self):
            return math.pi * self.raio ** 2
    
    
    class Quadrado(Forma):
        def __init__(self, lado):
            self.lado = lado
    
        def area(self):
            return self.lado ** 2
    
    
    for forma in (Circulo(1), Quadrado(2)):
        print(forma.descrever())
    
    Saída
    Circulo com área 3.14
    Quadrado com área 4.00
    

    O método descrever é concreto e usa o area abstrato: a classe base escreve o algoritmo e as filhas preenchem as lacunas. Esse padrão (método molde) é um dos usos mais úteis de classes abstratas.

    O erro vem cedo

    A diferença para o NotImplementedError do capítulo anterior é quando o erro aparece. Com ABC, tentar criar um objeto incompleto falha na criação, e não só quando o método ausente for chamado:

    intermediario/cap30_abstracao.pylinhas 45 a 58
    try:
        Forma()
    except TypeError as erro:
        print(erro)
    
    
    class Incompleta(Forma):
        pass
    
    
    try:
        Incompleta()
    except TypeError as erro:
        print(erro)
    
    Saída
    Can't instantiate abstract class Forma without an implementation for abstract method 'area'
    Can't instantiate abstract class Incompleta without an implementation for abstract method 'area'
    

    Abstração e encapsulamento não são a mesma coisa

    ConceitoPergunta que respondeFerramenta em Python
    EncapsulamentoO que eu escondo ou protejo dentro do objeto?Convenção _nome e @property
    AbstraçãoO que qualquer implementação precisa oferecer?ABC e @abstractmethod

    E o duck typing?

    Você não precisa de ABC para o polimorfismo funcionar. Eu uso classes abstratas quando existe uma família de implementações com comportamento comum (o método molde). Quando só importa a forma do objeto, a ferramenta mais leve é typing.Protocol, que mostro no nível avançado.

    Exercício 1

    Notificadores

    Crie a classe abstrata Notificador com o método enviar(mensagem), as implementações Email e SMS (que devolvem o texto "email: ..." e "sms: ...") e a função avisar(notificadores, mensagem) que devolve a lista de resultados.