
Héritage et polymorphisme
Découvrez l'héritage en Python : créez des classes filles qui héritent des attributs et méthodes de classes mères. Apprenez la surcharge de méthodes (method overriding), le polymorphisme, l'héritage multiple, et les classes abstraites (avec le module abc)
Héritage : créez des classes filles à partir de classes mères
L'héritage est l'un des concepts les plus puissants de la POO. Il vous permet de créer de nouvelles classes (classes filles) à partir de classes existantes (classes mères), en héritant de leurs attributs et de leurs méthodes. Cela favorise la réutilisation du code et vous permet de créer des hiérarchies de classes qui reflètent les relations entre les entités du monde réel.
En Python, vous indiquez qu'une classe hérite d'une autre classe en plaçant le nom de la classe mère entre parenthèses après le nom de la classe fille, dans la définition de la classe fille. Par exemple : `class Chien(Animal):`. Dans cet exemple, la classe `Chien` hérite de la classe `Animal`.
La classe fille hérite de tous les attributs et méthodes de la classe mère. Vous pouvez ensuite ajouter de nouveaux attributs et méthodes à la classe fille, ou modifier le comportement des méthodes héritées (surcharge de méthodes).
L'héritage vous permet de créer des classes plus spécialisées à partir de classes plus générales, en évitant de dupliquer le code.
Nous verrons des exemples d'héritage simple, et comment accéder aux attributs et méthodes de la classe mère depuis la classe fille.
Surcharge de méthodes (method overriding) : adaptez le comportement hérité
La surcharge de méthodes (method overriding) vous permet de modifier le comportement d'une méthode héritée dans une classe fille. Cela vous permet d'adapter le comportement de la classe fille aux spécificités de cette classe, tout en conservant le même nom de méthode.
Pour surcharger une méthode, il vous suffit de redéfinir la méthode dans la classe fille, avec le même nom et la même signature (même nombre et types de paramètres) que la méthode de la classe mère.
Lorsque vous appelez la méthode sur un objet de la classe fille, c'est la version surchargée de la méthode qui est exécutée, et non la version de la classe mère.
La surcharge de méthodes est un élément clé du polymorphisme, que nous verrons plus loin.
Nous verrons des exemples de surcharge de méthodes, et comment utiliser la fonction `super()` pour appeler la version de la classe mère d'une méthode surchargée.
Polymorphisme : utilisez des objets de différentes classes de manière interchangeable
Le polymorphisme (du grec "plusieurs formes") est la capacité d'utiliser des objets de différentes classes de manière interchangeable. Cela signifie que vous pouvez appeler la même méthode sur des objets de classes différentes, et chaque objet réagira de manière appropriée en fonction de sa propre implémentation de la méthode (grâce à la surcharge de méthodes).
Le polymorphisme rend votre code plus flexible et plus adaptable aux changements. Vous pouvez ajouter de nouvelles classes qui implémentent la même interface (les mêmes méthodes), sans avoir à modifier le code existant qui utilise ces classes.
Par exemple, imaginez que vous ayez une fonction `faire_du_bruit(animal)` qui prend un objet `animal` en argument et appelle sa méthode `faire_du_bruit()`. Grâce au polymorphisme, vous pouvez passer à cette fonction un objet de la classe `Chien`, un objet de la classe `Chat`, ou un objet de toute autre classe qui implémente la méthode `faire_du_bruit()`. Chaque objet fera le bruit approprié (aboiement, miaulement, etc.).
Nous verrons des exemples de polymorphisme, et comment il vous permet d'écrire du code plus générique et plus réutilisable.
Héritage multiple et ordre de résolution des méthodes (MRO)
Python supporte l'héritage multiple, ce qui signifie qu'une classe peut hériter de plusieurs classes mères. Cela peut être utile pour combiner des fonctionnalités de différentes classes, mais cela peut aussi rendre votre code plus complexe et plus difficile à comprendre.
Lorsque vous utilisez l'héritage multiple, il est important de comprendre l'ordre de résolution des méthodes (Method Resolution Order, MRO). Le MRO détermine dans quel ordre Python recherche une méthode lorsqu'elle est appelée sur un objet. Si plusieurs classes mères définissent la même méthode, Python utilisera la première méthode trouvée dans le MRO.
En Python, le MRO est calculé en utilisant l'algorithme C3. Vous pouvez obtenir le MRO d'une classe en utilisant l'attribut `__mro__` de la classe, ou la méthode `mro()`.
Nous verrons des exemples d'héritage multiple, comment fonctionne le MRO, et comment éviter les problèmes potentiels liés à l'héritage multiple (comme le "problème du diamant").
Classes abstraites et interfaces (module `abc`) : définissez des contrats
Une classe abstraite est une classe qui ne peut pas être instanciée directement. Elle sert de modèle pour d'autres classes (ses classes filles). Une classe abstraite peut contenir des méthodes abstraites, qui sont des méthodes sans implémentation (sans corps). Les classes filles doivent obligatoirement implémenter les méthodes abstraites de la classe mère.
Les classes abstraites sont utiles pour définir des interfaces, c'est-à-dire des contrats que les classes filles doivent respecter. Elles vous permettent de vous assurer que certaines méthodes seront présentes dans toutes les classes filles, et qu'elles auront une signature spécifique.
En Python, vous pouvez créer des classes abstraites en utilisant le module `abc` (Abstract Base Classes). Vous devez hériter de la classe `ABC`, et utiliser le décorateur `@abstractmethod` pour définir des méthodes abstraites.
Une interface, dans le contexte de Python, est généralement comprise comme un ensemble de méthodes qu'une classe doit implémenter. Bien que Python n'ait pas de mot-clé `interface` comme Java, les classes abstraites avec uniquement des méthodes abstraites servent souvent d'interfaces.
Nous verrons comment utiliser le module `abc` pour créer des classes abstraites, comment définir des méthodes abstraites, et comment les implémenter dans les classes filles. Nous discuterons également de la différence entre les classes abstraites et les interfaces, et de quand utiliser l'une ou l'autre.