0%
Programmation Orientée Objet en Python

POO

Structurez votre code avec des objets et des classes

10-15 min

Programmation Orientée Objet en Python

La Programmation Orientée Objet (POO) est un paradigme de programmation qui organise le code autour d’objets plutôt que de fonctions et de logique. Python, étant un langage multi-paradigme, offre un support complet et élégant pour la POO. Dans ce tutoriel, nous allons explorer les concepts fondamentaux de la POO en Python et comprendre comment les utiliser efficacement dans vos programmes.

Pourquoi utiliser la POO ?

Avant de plonger dans les détails, il est important de comprendre pourquoi la POO est si populaire :

  1. Organisation : La POO permet d’organiser votre code de manière plus structurée et modulaire.
  2. Réutilisation : Elle facilite la réutilisation du code grâce à l’héritage et à la composition.
  3. Maintenabilité : Un code bien structuré en objets est généralement plus facile à maintenir et à faire évoluer.
  4. Encapsulation : La POO permet de cacher la complexité et de protéger les données grâce à l’encapsulation.

Classes et objets

Les deux concepts fondamentaux en POO sont les classes et les objets.

Classes

Une classe est un modèle ou un plan pour créer des objets. Elle définit les attributs (variables) et les méthodes (fonctions) que les objets auront.

Voici comment définir une classe simple en Python :

class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age
    
    def saluer(self):
        return f"Bonjour, je m'appelle {self.nom} et j'ai {self.age} ans."

Dans cet exemple :

  • Personne est le nom de la classe.
  • __init__ est une méthode spéciale (constructeur) qui initialise un nouvel objet.
  • self fait référence à l’instance de l’objet en cours.
  • nom et age sont des attributs.
  • saluer est une méthode.

Objets

Un objet est une instance d’une classe. Pour créer un objet, vous appelez la classe comme une fonction :

personne1 = Personne("Alice", 30)
personne2 = Personne("Bob", 25)

print(personne1.saluer())  # Affiche: Bonjour, je m'appelle Alice et j'ai 30 ans.
print(personne2.saluer())  # Affiche: Bonjour, je m'appelle Bob et j'ai 25 ans.

Les objets personne1 et personne2 sont des instances distinctes de la classe Personne, chacune avec ses propres valeurs d’attributs.

Méthodes spéciales

Python offre plusieurs méthodes spéciales (également appelées méthodes magiques ou méthodes dunder pour “double underscore”) qui permettent de personnaliser le comportement des objets.

class Livre:
    def __init__(self, titre, auteur, pages):
        self.titre = titre
        self.auteur = auteur
        self.pages = pages
        self.page_actuelle = 0
    
    def __str__(self):
        """Définit comment l'objet est représenté sous forme de chaîne."""
        return f"{self.titre} par {self.auteur}"
    
    def __len__(self):
        """Définit le comportement quand la fonction len() est appliquée à l'objet."""
        return self.pages
    
    def __del__(self):
        """Méthode appelée lorsque l'objet est supprimé."""
        print(f"Le livre {self.titre} a été fermé.")

livre = Livre("Python Facile", "J. Dupont", 200)
print(livre)           # Utilise __str__
print(len(livre))      # Utilise __len__
del livre              # Déclenche __del__

Héritage

L’héritage permet à une classe d’hériter des attributs et méthodes d’une autre classe. C’est un concept fondamental pour promouvoir la réutilisation du code.

class Animal:
    def __init__(self, nom):
        self.nom = nom
    
    def parler(self):
        pass  # Méthode à surcharger dans les classes dérivées

class Chien(Animal):
    def parler(self):
        return f"{self.nom} dit Woof!"

class Chat(Animal):
    def parler(self):
        return f"{self.nom} dit Meow!"

animaux = [Chien("Rex"), Chat("Misty")]
for animal in animaux:
    print(animal.parler())

Dans cet exemple :

  • Animal est la classe de base (ou classe parente).
  • Chien et Chat sont des classes dérivées (ou classes enfants) qui héritent d’Animal.
  • La méthode parler est surchargée (redéfinie) dans chaque classe dérivée.

Héritage multiple

Contrairement à certains langages de programmation, Python supporte l’héritage multiple, ce qui permet à une classe d’hériter de plusieurs classes parentes.

class A:
    def methode_a(self):
        return "Méthode de A"

class B:
    def methode_b(self):
        return "Méthode de B"

class C(A, B):  # Hérite de A et B
    def methode_c(self):
        return "Méthode de C"

objet = C()
print(objet.methode_a())  # Hérité de A
print(objet.methode_b())  # Hérité de B
print(objet.methode_c())  # Défini dans C

Encapsulation

L’encapsulation est le concept de regroupement des données et des méthodes qui opèrent sur ces données, et de restreindre l’accès direct aux variables d’un objet.

En Python, l’encapsulation est obtenue par convention plutôt que par application stricte :

class CompteBancaire:
    def __init__(self, solde_initial):
        self._solde = solde_initial  # Convention: attribut protégé (single underscore)
        self.__compte_id = "123456"  # Convention: attribut privé (double underscore)
    
    def deposer(self, montant):
        self._solde += montant
    
    def retirer(self, montant):
        if montant <= self._solde:
            self._solde -= montant
            return True
        return False
    
    def get_solde(self):
        return self._solde

compte = CompteBancaire(1000)
compte.deposer(500)
print(compte.get_solde())  # 1500
print(compte._solde)       # Accessible, mais par convention, ne devrait pas être accédé directement
# print(compte.__compte_id)  # Erreur: renommage par "name mangling"
print(compte._CompteBancaire__compte_id)  # Accessible via mangling

En Python :

  • Un attribut avec un simple underscore (_solde) indique qu’il est protégé (convention, non appliqué).
  • Un attribut avec un double underscore (__compte_id) est soumis au “name mangling” (renommage), ce qui le rend plus difficile à accéder accidentellement, mais pas vraiment privé.

Polymorphisme

Le polymorphisme permet aux objets de différentes classes d’être traités comme des objets d’une classe commune. En Python, le polymorphisme est intrinsèque au langage grâce au duck typing.

def faire_parler(animal):
    print(animal.parler())

chien = Chien("Rex")
chat = Chat("Misty")

faire_parler(chien)  # Rex dit Woof!
faire_parler(chat)   # Misty dit Meow!

La fonction faire_parler fonctionne avec n’importe quel objet qui a une méthode parler, sans se soucier de sa classe concrète.

Propriétés

Les propriétés permettent de contrôler l’accès aux attributs d’une classe tout en maintenant une interface propre.

class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("La température ne peut pas être inférieure au zéro absolu.")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        self.celsius = (value - 32) * 5/9

temp = Temperature()
temp.celsius = 25
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

temp.fahrenheit = 77
print(f"Celsius: {temp.celsius}°C, Fahrenheit: {temp.fahrenheit}°F")

Méthodes et attributs de classe

Contrairement aux méthodes et attributs d’instance qui sont propres à chaque objet, les méthodes et attributs de classe sont partagés par toutes les instances de la classe.

class Voiture:
    # Attribut de classe
    nombre_de_voitures = 0
    
    def __init__(self, marque, modele):
        self.marque = marque
        self.modele = modele
        # Incrémenter l'attribut de classe
        Voiture.nombre_de_voitures += 1
    
    @classmethod
    def get_nombre_de_voitures(cls):
        return cls.nombre_de_voitures
    
    @staticmethod
    def est_electrique(marque, modele):
        # Une méthode statique qui ne dépend pas de l'état de l'instance
        # Liste fictive de voitures électriques
        voitures_electriques = [("Tesla", "Model 3"), ("Nissan", "Leaf")]
        return (marque, modele) in voitures_electriques

voiture1 = Voiture("Toyota", "Corolla")
voiture2 = Voiture("Honda", "Civic")

print(Voiture.get_nombre_de_voitures())  # 2
print(Voiture.est_electrique("Tesla", "Model 3"))  # True

Conclusion

La programmation orientée objet en Python offre une manière puissante et flexible d’organiser votre code. Elle vous permet de créer des programmes plus modulaires, réutilisables et maintenables.

Dans ce tutoriel, nous avons couvert les concepts fondamentaux de la POO en Python, y compris les classes, les objets, l’héritage, le polymorphisme et l’encapsulation. Mais ce n’est que le début ! Il existe de nombreux autres concepts avancés et patterns de conception qui peuvent vous aider à tirer le meilleur parti de la POO.

Dans le prochain tutoriel, nous explorerons la gestion des exceptions en Python, un aspect crucial pour écrire des programmes robustes.

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !