POO
Structurez votre code avec des objets et des classes
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 :
- Organisation : La POO permet d’organiser votre code de manière plus structurée et modulaire.
- Réutilisation : Elle facilite la réutilisation du code grâce à l’héritage et à la composition.
- Maintenabilité : Un code bien structuré en objets est généralement plus facile à maintenir et à faire évoluer.
- 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
etage
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
etChat
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