← algo
TP · Python — Fonctions avancées, fichiers & POO

Python orienté objet

Un TP de gestion d'étudiants qui parcourt les fonctions avancées (*args, lambda), les fichiers, puis la POO : encapsulation, héritage et polymorphisme.

Exercice 1
★★

Arguments variables (*args)

Une moyenne d'un nombre quelconque de notes

Énoncé

Une fonction calculer_moyenne_generale() qui accepte un nombre variable de notes et retourne la moyenne (ou None si aucune note).

*notes capture les arguments dans un tuple
calculer_moyenne_generale(12, 15, 18, 14)
notes →(12, 15, 18, 14)tuple de 4
moyenne
14.75
def calculer_moyenne_generale(*notes):
    if len(notes) == 0:
        return None
    return sum(notes) / len(notes)
À retenir

*notes rassemble tous les arguments positionnels dans un tuple. On teste le cas vide avant de diviser.

Exercice 2
★★

Tri avancé avec lambda

Classer les étudiants par moyenne décroissante

Énoncé

À partir d'une liste de tuples (nom, n1, n2, n3), trier les étudiants par moyenne décroissante avec une fonction lambda.

Tri à bulles par moyenne
13.7
Ali
17.0
🎓
Sara
11.0
Karim
15.0
🎓
Lina
01 / 11
Tableau initial — on trie par moyenne décroissante
etudiants.sort(
  key=lambda e: sum(e[1:]) / len(e[1:]),
  reverse=True
)

La fonction lambda sert de clé de tri : Python l'évalue sur chaque élément et range selon le résultat. reverse=True ⟶ ordre décroissant. (🎓 = boursier)

À retenir

La lambda fournit la clé de comparaison. L'animation montre un tri à bulles, mais Python utilise un tri bien plus efficace (Timsort).

Exercice 3
★★

Gestion de fichiers

Écrire puis relire etudiants.txt

Énoncé

Créer un fichier au format nom;n1;n2;n3, puis le relire pour afficher la moyenne de chaque étudiant.

etudiants.txt — lecture ligne par ligne
Ali;12;15;14
Sara;18;16;17
Karim;10;11;12
Lina;15;15;15
split(";") → ["Ali", "12", "15", "14"]
moyenne → 13.67
01 / 05
Lecture de Ali
with open("etudiants.txt", "r") as f:
    for ligne in f:
        ligne = ligne.strip()    # enlève le \n
        if ligne:
            nom, n1, n2, n3 = ligne.split(";")
            moyenne = (int(n1)+int(n2)+int(n3))/3
            print(f"{nom}: {moyenne:.2f}")
À retenir

with ferme le fichier automatiquement. strip() enlève le \n, split(";") découpe la ligne, et int() convertit les notes.

Exercice 4
★★★

Classe & encapsulation

Attributs privés et validation

Énoncé

Une classe Etudiant avec attributs privés, getters via @property, validation des notes (0–20) et méthodes __str__ / __repr__.

Diagramme de classe
Etudiantprivé : __
__nom
__notes[]
nom (property)
moyenne (property)
set_note(i, v) → valide 0–20
__str__ / __repr__

Le double __ rend l'attribut privé ; @property expose une lecture contrôlée. La validation est centralisée dans une méthode privée.

class Etudiant:
    def __init__(self, nom, n1, n2, n3):
        self.__nom = nom
        self.__notes = [self.__valider(n)
                        for n in (n1, n2, n3)]

    def __valider(self, note):
        if not (0 <= note <= 20):
            raise ValueError("note invalide")
        return note

    @property
    def moyenne(self):
        return sum(self.__notes) / len(self.__notes)
À retenir

L'encapsulation protège l'état interne : on ne peut pas poser une note invalide « par la porte de derrière ». __str__ est lisible, __repr__ est technique.

Exercice 5
★★★

Héritage

EtudiantBoursier hérite d'Etudiant

Énoncé

Une classe EtudiantBoursier qui hérite d'Etudiant, avec un attribut montant_bourse et une méthode ajuster_bourse().

Héritage : Boursier est un Étudiant
Etudiant
__nom
__notes[]
moyenne
__str__
hérite de
EtudiantBoursier
+ __montant_bourse
ajuster_bourse()
__str__ (super + bourse)
class EtudiantBoursier(Etudiant):
    def __init__(self, nom, n1, n2, n3, bourse):
        super().__init__(nom, n1, n2, n3)
        self.__montant_bourse = bourse

    def ajuster_bourse(self):
        if self.moyenne >= 14:        # hérité
            self.__montant_bourse *= 1.10
            return True
        return False

super().__init__() initialise la partie héritée ; la sous-classe ajoute montant_bourseet réutilise self.moyenne du parent.

À retenir

« Boursier est un Étudiant » : il réutilise tout le parent via super() et n'ajoute que ce qui le distingue.

Exercice 6
★★★

Polymorphisme & synthèse

Une Promotion qui gère les deux types

Énoncé

Une classe Promotion qui gère une liste d'étudiants : ajout (avec contrôle de type), classement, moyenne de promotion et sauvegarde.

Promotion : une liste, deux types
Promotion « L1 Info 2026 »
1. Sara Boursier17.00/20 · 2000 DH
2. Lina Boursier15.00/20 · 1500 DH
3. Ali Etudiant13.67/20
4. Karim Etudiant11.00/20
moyenne promo14.17
class Promotion:
    def ajouter(self, etudiant):
        if isinstance(etudiant, Etudiant):  # accepte aussi
            self.__etudiants.append(etudiant) # les sous-classes
        else:
            raise TypeError("Doit être un Etudiant")

    def afficher_classement(self):
        self.__etudiants.sort(key=lambda e: e.moyenne,
                              reverse=True)

Polymorphisme : la liste contient des Etudiant et desEtudiantBoursier sans distinction. e.moyenne et str(e) font « ce qu'il faut » selon le type réel de chaque objet.

À retenir

La même liste contient Etudiant et EtudiantBoursier. Grâce au polymorphisme, e.moyenne et str(e) s'adaptent au type réel — le code de Promotion n'a pas à savoir lequel est lequel.