0 XP
?
Python : de zéro à la maîtrise/Programmation orientée objet
Intermédiaire50 min35 XP

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

ElementSyntaxeDescription
Classeclass Nom:Le plan de construction
__init__def __init__(self):Constructeur
selfPremier parametreReference a l'objet lui-meme
Attributself.nomVariable de l'objet
Methodedef 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

💡 self permet 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 🔒

ConventionSignificationExemple
attrPublicself.nom
_attrProtege (convention)self._solde
__attrprive (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

MethodeSignificationQuand
__init__ConstructeurCreation de l'objet
__str__Representation texteprint(obj), str(obj)
__repr__Representation officiellerepr(obj), REPL
__add__Additionobj1 + obj2
__eq__Egaliteobj1 == obj2
__len__Longueurlen(obj)
__contains__Appartenancex in obj
__getitem__Indexationobj[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/8
📝 Pseudo-code
1class Animal:
2 def __init__(self, nom):
3 self.nom = nom
4 def parler(self):
5 return f"{self.nom} fait un bruit"
6
7chat = Animal("Minou")
8print(chat.parler())
⚙️ Exécution
📦 Mémoire
Aucune variable
🔀 Flux d'exécution
class Animal
3
Définition de classe

Le mot-clé class définit une nouvelle classe. Animal est un modèle (blueprint) pour créer des objets.