Comprendre les Abstract Base Classes (ABCs) en Python
Article publié le 08/05/2025 par Jules SAGOT
Dans cet article, je vais vous présenter à quoi peuvent servir les Abstract Base Classes dans votre projet Python.
Les ABC ont été introduites par la PEP 3119.
Les bases : à quoi sert une classe abstraite en programmation ?
Une classe abstraite permet de définir un contrat que respectent les classes concrètes, et parfois de fournir une implémentation.
Dans nos algorithmes, on peut ensuite utiliser une instance de classe qui hérite de la classe abstraite de manière interchangeable.
Par exemple, dans le code suivant la fonction animal_says
fonctionne
avec une instance de classe qui respecte le contrat de Animal
.
from abc import ABCMeta, abstractmethod
# Abstract class defining the contract
class Animal(metaclass=ABCMeta):
@abstractmethod
def make_sound(self):
pass
# Concrete class implementing the contract
class Dog(Animal):
def make_sound(self):
return "Woof!"
# Another concrete class implementing the contract
class Cat(Animal):
def make_sound(self):
return "Meow!"
# Function that works with any Animal
def animal_says(animal: Animal):
print(animal.make_sound())
# Using the function with different concrete classes
dog = Dog()
cat = Cat()
animal_says(dog) # Output: Woof!
animal_says(cat) # Output: Meow!
💡 Une class abstraite ne peut pas être instanciée :
Animal() # TypeError: Can't instantiate abstract class Animal with abstract method make_sound
Est-ce que les ABC remplacent le Duck Typing ?
Le duck typing en Python repose sur l’idée que “si ça marche comme un canard, c’est un canard”.
Plutôt que de vérifier le type d’un objet, on vérifie s’il possède les méthodes ou attributs nécessaires.
Pour cela on peut utiliser la fonction builtin hasattr
qui de
vérifier si un objet implémente un attribut ou méthode :
class Dog:
def make_sound(self):
return "Woof!"
class Cat:
def make_sound(self):
return "Meow!"
# Function that works with any instance that behaves like an animal
def animal_says(animal):
if not hasattr(animal, "make_sound"):
raise AttributeError("Animal must make_sound")
print(animal.make_sound())
# Using the function with different concrete classes
dog = Dog()
cat = Cat()
animal_says(dog) # Output: Woof!
animal_says(cat) # Output: Meow!
Le Duck Typing est toujours utilisé dans Python3.
Par exemple, vous pouvez toujours passer à sys.stdout n’importe quel objet, tant qu’il possède une méthode write :
import sys
class MyWriter:
def write(self, text):
raise Exception(f"Intercepted: {text}")
sys.stdout = MyWriter()
print("Hello") # Exception: Intercepted: Hello
Les ABC ne remplacent pas le duck typing.
Ces deux concepts permettent de vérifier qu’une classe respecte un contrat.
Alors pourquoi avoir introduit les Abstract Base Classes dans Python3 ?
Premier exemple : la class abstraite Iterable
En Python, pour créer un Iterable
, on doit déclarer une méthode
__iter__
dans notre classe.
Il existe une ABC qui déclare ce contrat : from collections.abc import Iterable
.
Pour respecter ce contrat, pas besoin d’hériter d’Iterable
:
from collections.abc import Iterable
class MyIterable:
def __iter__(self):
yield 42
isinstance(MyIterable(), Iterable) # True !
En fait, quand on appelle isinstance
, python va vérifier si notre
instance respecte le contrat décrit dans la l’ABC.
Regardons maintenant le code source de l’ABC Iterable dans CPython :
from abc import ABCMeta
class Iterable(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is Iterable:
return _check_methods(C, "__iter__")
return NotImplemented
__class_getitem__ = classmethod(GenericAlias)
En Python, une classe abstrait de base permet de définir les tests qui permettent de déterminer si oui ou non une classe est une instance d’une autre.
Avec ce code, on voit qu’une classe est Iterable
si elle dispose
d’une méthode __iter__
.
Deuxième exemple : le module numbers
La PEP 3141 a défini des ABC pour les types numériques.
Vous pouvez maintenant remplacer le code suivant :
my_number = 42.42
if isinstance(my_number, int) or isinstance(my_number, float):
my_number += 1
Par ce nouveau code :
from numbers import Number
my_number = 42.42
if isinstance(my_number, Number):
my_number += 1
On a ainsi pu remplacer deux tests par un seul, rendre plus expressif notre code, et déléguer la validation de notre instance par une ABC
Conclusion
En conclusion, les Abstract Base Classes (ABC) permettent d’exprimer clairement les contrats que doivent respecter vos objets.
Votre objet peut ensuite continuer uniquement d’implémenter le contrat (Duck Typing), ou bien d’hériter de la classe abstraite qu’il implémente.
Les classes abstraites facilitent la lisibilité, la validation et l’interopérabilité de vos classes - sans sacrifier la flexibilité propre à Python.
Utilisées à bon escient, elles renforcent la robustesse de votre code.