Classes et objets Python : le tutoriel 2026
La plupart des didacticiels Python POO enseignent la syntaxe et ignorent le modèle mental. Celui-ci fait le contraire : vous repartirez avec une image claire de ce qu'est une classe au moment de l'exécution, quand rechercher @dataclass au lieu d'écrire __init__ à la main, et comment self fonctionne vraiment (ce n'est pas magique).
Nous aborderons : la classe viable minimale de quatre lignes, pourquoi « self » est un paramètre, les attributs de classe par rapport à l'instance (le bug n°1 pour les débutants), les six méthodes de dunder que vous verrez partout, « @dataclass » comme valeur par défaut moderne, et une règle stricte pour savoir quand laisser les classes tranquilles et utiliser une fonction simple.
Le modèle mental : une classe est une usine
Une classe en Python est une usine qui produit des objets. Chaque fois que vous appelez « Rect(3, 4) », Python crée un nouvel objet avec son propre stockage et vous le rend.
C'est toute la mécanique. La classe est le modèle ; chaque appel Rect(...) est un tampon du plan dans une nouvelle RAM.
self n'est qu'un paramètre
La confusion n°1 pour les personnes venant de JS ou Ruby : self en Python est explicit. Le premier paramètre de chaque méthode est une référence à l’instance appelée.
Donc c.bump() est du sucre syntaxique pour Counter.bump(c). Python transmet l'instance comme premier argument. Vous pouvez l'appeler « moi », « ceci » ou « foo » — « self » est une convention, pas un mot-clé. Restez fidèle à « self » (PEP 8) pour que d'autres développeurs Python puissent lire votre code.
Le piège des attributs classe vs instance
Le bug Python POO le plus courant dans une base de code débutant :
items = [] dans la portée de la classe crée UNE liste partagée par chaque instance. a.add("milk") le mute, donc b.items voit la même liste.
Règle : initialiser l'état mutable dans `__init__`, pas dans la portée de la classe.
Ce bug a été envoyé en production plus de fois que n'importe quel développeur Python ne l'admettrait. Surveillez les listes, les dicts et les ensembles dans la portée de la classe.
Les six méthodes que vous verrez partout
Les méthodes Dunder (__name__) sont les hooks de surcharge d'opérateurs de Python. Ces six couvrent 95 % de ce que vous rencontrerez :
1. __init__(self, ...) — constructeur
S'exécute lorsque l'objet est créé. Définissez les attributs de l'instance ici. Ne renvoie rien (Python applique « Aucun »).
2. __repr__(self) — chaîne destinée aux développeurs
Appelé par print(x) si __str__ est manquant, et toujours par le REPL. Visez quelque chose que vous pourriez recoller dans Python pour recréer l'objet :
3. __eq__(soi, autre) — égalité
Sans cela, Rect(3, 4) == Rect(3, 4) renvoie False (la valeur par défaut est l'identité). Comparez champ par champ :
4. __hash__(self) — capacité de hachage
Si vous remplacez __eq__, vous DEVEZ également remplacer __hash__ ou Python définit __hash__ = None (l'objet devient impossible à hacher). Le plus simple : return hash((self.width, self.height)).
5. __len__(self) — pour len(obj)
Fait fonctionner len(cart) == 5.
6. __iter__(self) — pour for x in obj :
Renvoie un itérateur. yield à l'intérieur rend la classe itérable :
@dataclass — la valeur par défaut moderne
Si votre classe est principalement un détenteur de données (trois champs, un __init__, un __repr__, un __eq__), arrêtez d'écrire ce passe-partout. @dataclass génère tout cela à partir de vos annotations de type :
Ce sont __init__, __repr__ et __eq__ tous générés. Ajoutez @dataclass(frozen=True) pour rendre l'objet immuable ET obtenez __hash__ gratuitement.
Règle : recherchez d'abord `@dataclass`. Écrivez une classe générée manuellement uniquement lorsque vous avez besoin de méthodes qui ne sont pas des accesseurs d'attribut.
__slots__ — optimisation de la mémoire (avancée)
Par défaut, chaque instance porte un __dict__ afin que vous puissiez ajouter des attributs arbitraires. __slots__ échange cette dictée contre une structure fixe de niveau C — une empreinte RAM plus petite et un accès plus rapide aux attributs :
Utilisez __slots__ lorsque : (a) vous créez des millions d'instances et des problèmes de RAM, ou (b) vous souhaitez détecter l'attribution d'attributs typés au moment de l'exécution. Sinon, ignorez-le - il désactive le cornichon par défaut et rompt l'héritage multiple de manière subtile.
Quand laisser les cours tranquilles
Règle stricte : si votre classe a UNE méthode plus `__init__`, cela devrait probablement être une fonction.
Les classes gagnent leur poids lorsqu'elles détiennent state sur plusieurs appels de méthode, ou lorsqu'elles implémentent un protocole bien défini (__iter__, __enter__, __eq__, etc.). La logique ponctuelle est une fonction.
Héritage – utilisez-le avec parcimonie
L'héritage est réel mais surutilisé. En Python 2026, préférez composition — conservez un autre objet comme attribut au lieu d'en hériter :
N'héritez que lorsque vous avez une véritable relation "est-un" ET que vous souhaitez remplacer le comportement. Un NamedRect qui hérite de Rect pour ajouter un champ name convient. Construire une hiérarchie d'héritage à cinq niveaux pour une classe de logique métier est un code que vous démêlerez dans 6 mois.
Les classes sont l’une des fonctionnalités les plus puissantes de Python et l’une des plus faciles à utiliser. Le modèle mental qui aide : une classe est une usine pour les objets, "self" est un paramètre simple, l'état mutable entre dans "__init__", recherchez d'abord "@dataclass" et revenez à une fonction chaque fois que la classe a moins de deux méthodes porteuses d'état.
Prochaine étape : 30 leçons pratiques de POO couvrant les cours, @dataclass, l'héritage par rapport à la composition et les méthodes dunder - avec du vrai Python exécuté dans votre navigateur et un mentor IA à chaque étape.