Chapter 30, Intermediate
Abstraction with ABC
An abstract class defines a contract that subclasses are required to fulfill. It's a way of saying "any class that does X needs to have these methods".
Code for this chapter: intermediario/cap30_abstracao.py
The contract
The module abc provides ABC and @abstractmethod. A class with abstract methods cannot be instantiated. Subclasses need to implement all of them:
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())
Circulo com área 3.14
Quadrado com área 4.00
The method descrever is concrete and uses the area abstract: the base class writes the algorithm and the subclasses fill in the gaps. This pattern (template method) is one of the most useful uses of abstract classes.
The error comes early
The difference from the NotImplementedError in the previous chapter is when where the error appears. With ABC, trying to create an incomplete object fails at creation, and not just when the missing method is called:
try:
Forma()
except TypeError as erro:
print(erro)
class Incompleta(Forma):
pass
try:
Incompleta()
except TypeError as erro:
print(erro)
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'
Abstraction and encapsulation are not the same thing
| Concept | Question it answers | Tool in Python |
|---|---|---|
| Encapsulation | What do I hide or protect inside the object? | Convention _nome and @property |
| Abstraction | What does any implementation need to offer? | ABC and @abstractmethod |
And what about duck typing?
You don't need
ABCfor polymorphism to work. I use abstract classes when there is a family of implementations with common behavior (the mold method). When only the shape of the object matters, the lighter tool istyping.Protocol, which I show at the advanced level.
Exercise 1
Notifiers
Create the abstract class Notificador with the method enviar(mensagem), the implementations Email and SMS (that return the text "email: ..." and "sms: ...") and the function avisar(notificadores, mensagem) that returns the list of results.