Objectifs de cette leçon
- Définir une classe avec des attributs et méthodes
- Créer des instances d'une classe
- Utiliser l'héritage pour factoriser du code
Programmation orientee objet 🏗️
Qu'est-ce que la POO ? 🤔
La Programmation Orientee Objet (POO) organise le code autour d'objets : des entites qui combinent des donnees (attributs) et des comportements (methodes).
💡 Pense a une voiture : elle a des proprietes (couleur, vitesse, marque) et des actions (accelerer, freiner). Une classe est le plan, un objet est la voiture construite.
Creer une classe 🏗️
class Voiture: """Classe representant une voiture.""" def __init__(self, marque, couleur, vitesse_max=200): self.marque = marque self.couleur = couleur self.vitesse_max = vitesse_max self.vitesse_actuelle = 0 def accelerer(self, increment=10): if self.vitesse_actuelle + increment <= self.vitesse_max: self.vitesse_actuelle += increment print(f"Vitesse : {self.vitesse_actuelle} km/h") else: print(f"Vitesse max atteinte : {self.vitesse_max} km/h") def freiner(self, decrement=10): self.vitesse_actuelle = max(0, self.vitesse_actuelle - decrement) print(f"Vitesse : {self.vitesse_actuelle} km/h") def __str__(self): return f"{self.marque} ({self.couleur})" voiture1 = Voiture("Tesla", "rouge", 250) voiture2 = Voiture("Peugeot", "bleue") voiture1.accelerer() # Vitesse : 10 km/h voiture1.accelerer(50) # Vitesse : 60 km/h voiture1.freiner(20) # Vitesse : 40 km/h print(voiture1) # Tesla (rouge)
Les cles
| Element | Syntaxe | Description |
|---|---|---|
| Classe | class Nom: | Le plan de construction |
__init__ | def __init__(self): | Constructeur |
self | Premier parametre | Reference a l'objet lui-meme |
| Attribut | self.nom | Variable de l'objet |
| Methode | def methode(self): | Fonction de l'objet |
__init__ et self 🔑
class Etudiant: def __init__(self, nom, age, filiere): self.nom = nom self.age = age self.filiere = filiere self.notes = [] def ajouter_note(self, note): self.notes.append(note) def moyenne(self): if not self.notes: return 0 return sum(self.notes) / len(self.notes) alice = Etudiant("Alice", 22, "Informatique") alice.ajouter_note(15) alice.ajouter_note(18) alice.ajouter_note(12) print(f"{alice.nom} : moyenne = {alice.moyenne():.1f}") # Alice : moyenne = 15.0
💡
selfpermet a la methode d'acceder aux attributs de l'objet qui l'appelle.
Proprietes et @property 🎯
class CompteBancaire: def __init__(self, titulaire, solde=0): self.titulaire = titulaire self._solde = solde @property def solde(self): return self._solde @solde.setter def solde(self, valeur): if valeur < 0: raise ValueError("Le solde ne peut pas etre negatif") self._solde = valeur compte = CompteBancaire("Alice", 1000) print(compte.solde) # 1000 compte.solde = 500 print(compte.solde) # 500
Encapsulation 🔒
| Convention | Signification | Exemple |
|---|---|---|
attr | Public | self.nom |
_attr | Protege (convention) | self._solde |
__attr | prive (name mangling) | self.__secret |
class CompteEpargne: def __init__(self, solde=0): self.__solde = solde # prive def deposer(self, montant): if montant > 0: self.__solde += montant def retirer(self, montant): if 0 < montant <= self.__solde: self.__solde -= montant return True return False @property def solde(self): return self.__solde compte = CompteEpargne(1000) compte.deposer(500) print(compte.solde) # 1500 compte.retirer(200) print(compte.solde) # 1300
Heritage 🧬
L'heritage permet de creer une nouvelle classe a partir d'une classe existante.
class Animal: def __init__(self, nom, espece): self.nom = nom self.espece = espece def parler(self): return "..." def __str__(self): return f"{self.nom} ({self.espece})" class Chien(Animal): def __init__(self, nom, race): super().__init__(nom, espece="Chien") self.race = race def parler(self): return "Wouf ! 🐕" class Chat(Animal): def __init__(self, nom, couleur): super().__init__(nom, espece="Chat") self.couleur = couleur def parler(self): return "Miaou ! 🐱" # Utilisation rex = Chien("Rex", "Berger allemand") felix = Chat("Felix", "tigre") print(rex) # Rex (Chien) print(rex.parler()) # Wouf ! 🐕 print(felix) # Felix (Chat) print(felix.parler()) # Miaou ! 🐱
super() — appeler le constructeur parent
class Employe: def __init__(self, nom, salaire): self.nom = nom self.salaire = salaire class Manager(Employe): def __init__(self, nom, salaire, departement): super().__init__(nom, salaire) self.departement = departement mgr = Manager("Alice", 50000, "IT") print(f"{mgr.nom} travaille en {mgr.departement}")
Polymorphisme 🔄
Le polymorphisme permet d'utiliser la meme interface avec des types differents.
class Forme: def aire(self): raise NotImplementedError def perimetre(self): raise NotImplementedError class Cercle(Forme): def __init__(self, rayon): self.rayon = rayon def aire(self): import math return math.pi * self.rayon ** 2 def perimetre(self): import math return 2 * math.pi * self.rayon class Rectangle(Forme): def __init__(self, largeur, hauteur): self.largeur = largeur self.hauteur = hauteur def aire(self): return self.largeur * self.hauteur def perimetre(self): return 2 * (self.largeur + self.hauteur) # Polymorphisme : meme fonction, comportements differents def afficher_infos(forme): print(f"Aire : {forme.aire():.2f}") print(f"Perimetre : {forme.perimetre():.2f}") cercle = Cercle(5) rect = Rectangle(4, 6) afficher_infos(cercle) # Aire : 78.54 # Perimetre : 31.42 afficher_infos(rect) # Aire : 24.00 # Perimetre : 20.00
Diagramme de classe 📊
Methodes speciales (dunder methods) ✨
class Vecteur2D: def __init__(self, x, y): self.x = x self.y = y def __add__(self, autre): return Vecteur2D(self.x + autre.x, self.y + autre.y) def __mul__(self, scalaire): return Vecteur2D(self.x * scalaire, self.y * scalaire) def __repr__(self): return f"Vecteur2D({self.x}, {self.y})" def __eq__(self, autre): return self.x == autre.x and self.y == autre.y def __len__(self): import math return int(math.sqrt(self.x**2 + self.y**2)) v1 = Vecteur2D(3, 4) v2 = Vecteur2D(1, 2) print(v1 + v2) # Vecteur2D(4, 6) print(v1 * 3) # Vecteur2D(9, 12) print(v1 == v2) # False print(len(v1)) # 5
Les methodes speciales les plus courantes
| Methode | Signification | Quand |
|---|---|---|
__init__ | Constructeur | Creation de l'objet |
__str__ | Representation texte | print(obj), str(obj) |
__repr__ | Representation officielle | repr(obj), REPL |
__add__ | Addition | obj1 + obj2 |
__eq__ | Egalite | obj1 == obj2 |
__len__ | Longueur | len(obj) |
__contains__ | Appartenance | x in obj |
__getitem__ | Indexation | obj[key] |
Bonnes pratiques ✅
# 1. Utiliser des noms explicites class GestionnaireDeBibliotheque: # ✅ pass class GDB: # ❌ Trop cryptique pass # 2. Preferer la composition a l'heritage class Voiture: def __init__(self): self.moteur = Moteur() # Composition self.roues = [Roue() for _ in range(4)] # 3. Respecter le principe de substitution de Liskov # Les sous-classes doivent pouvoir remplacer la classe parent # 4. Un faire une seule chose (SRP)
Exercice pour toi 🎯
# Exercice 1 : Systeme bancaire class Compte: def __init__(self, titulaire, solde=0): self.titulaire = titulaire self._solde = solde @property def solde(self): return self._solde def deposer(self, montant): if montant > 0: self._solde += montant return True return False def retirer(self, montant): if 0 < montant <= self._solde: self._solde -= montant return True return False class CompteEpargne(Compte): def __init__(self, titulaire, solde=0, taux=0.02): super().__init__(titulaire, solde) self.taux = taux def appliquer_interets(self): interets = self._solde * self.taux self._solde += interets print(f"Interets : +{interets:.2f}e") compte = CompteEpargne("Alice", 1000, 0.05) compte.deposer(500) print(f"Solde : {compte.solde}e") # 1500e compte.appliquer_interets() print(f"Solde : {compte.solde}e") # 1575e
💡 Astuce : La POO est partout en Python. Comprends-la et tu pourras lire et utiliser n'importe quelle bibliotheque ! 🚀
⚡ Simulateur — POO en Python
Étape 1/8Le mot-clé class définit une nouvelle classe. Animal est un modèle (blueprint) pour créer des objets.