# Corrigé de l'exercice — Cuisson des pâtes --- ## Énoncé Nous voulons faire cuire des pâtes. Écrire la recette sous forme de code Python selon trois paradigmes différents. --- ## Version impérative Liste d'instructions étape par étape, avec modification d'état. ```python # Version impérative : liste d'instructions étape par étape def cuire_pates_imperatif(): """Fait cuire des pâtes de manière impérative.""" # État initial eau = "froide" pates = "crues" sel = False # Étape 1 : Remplir la casserole print("Remplissage de la casserole...") quantite_eau = 1.5 # litres # Étape 2 : Faire chauffer l'eau print("Chauffage de l'eau...") eau = "chaude" # Étape 3 : Attendre l'ébullition print("Attente de l'ébullition...") eau = "bouillante" # Étape 4 : Saler l'eau print("Ajout du sel...") sel = True # Étape 5 : Ajouter les pâtes print("Ajout des pâtes...") pates = "en cuisson" # Étape 6 : Attendre le temps de cuisson temps_cuisson = 10 # minutes print(f"Cuisson pendant {temps_cuisson} minutes...") # Étape 7 : Égoutter print("Égouttage des pâtes...") pates = "cuites" print(f"Résultat : pâtes {pates}") return pates # Exécution resultat = cuire_pates_imperatif() ``` **Caractéristiques :** - Modification d'état (variables `eau`, `pates`, `sel`) - Instructions séquentielles - Effets de bord (print) --- ## Version fonctionnelle Une fonction pure qui prend un état et retourne un nouvel état, sans modification. ```python # Version fonctionnelle : fonctions pures et composition def remplir_casserole(etat): """Retourne un nouvel état avec la casserole remplie.""" return {**etat, "eau": "froide", "quantite_eau": 1.5} def chauffer_eau(etat): """Retourne un nouvel état avec l'eau chauffée.""" return {**etat, "eau": "chaude"} def faire_bouillir(etat): """Retourne un nouvel état avec l'eau bouillante.""" return {**etat, "eau": "bouillante"} def saler(etat): """Retourne un nouvel état avec le sel ajouté.""" return {**etat, "sel": True} def ajouter_pates(etat): """Retourne un nouvel état avec les pâtes en cuisson.""" return {**etat, "pates": "en cuisson"} def cuire(etat, duree): """Retourne un nouvel état après cuisson.""" return {**etat, "temps_cuisson": duree, "pates": "cuites"} def egoutter(etat): """Retourne un nouvel état avec les pâtes égouttées.""" return {**etat, "egouttees": True} # Composition de fonctions def cuire_pates_fonctionnel(etat_initial): """ Fait cuire des pâtes de manière fonctionnelle. Chaque étape retourne un nouvel état sans modifier l'ancien. """ etat = remplir_casserole(etat_initial) etat = chauffer_eau(etat) etat = faire_bouillir(etat) etat = saler(etat) etat = ajouter_pates(etat) etat = cuire(etat, 10) etat = egoutter(etat) return etat # Version encore plus fonctionnelle avec reduce import functools def cuire_pates_reduce(etat_initial): """Version avec reduce pour composer les fonctions.""" etapes = [ remplir_casserole, chauffer_eau, faire_bouillir, saler, ajouter_pates, lambda e: cuire(e, 10), egoutter ] return functools.reduce(lambda etat, f: f(etat), etapes, etat_initial) # Exécution etat_initial = {"pates": "crues", "sel": False} resultat = cuire_pates_fonctionnel(etat_initial) print(f"État final : {resultat}") # Vérification : l'état initial n'a pas été modifié print(f"État initial préservé : {etat_initial}") ``` **Caractéristiques :** - Pas de modification d'état (immutabilité) - Fonctions pures (même entrée → même sortie) - Composition de fonctions - L'état initial n'est jamais modifié --- ## Version orientée objet Une classe `Pates` avec des attributs et une méthode `cuire()`. ```python # Version orientée objet : classe Pates avec méthode cuire() class Casserole: """Représente une casserole pour la cuisson.""" def __init__(self): self.eau = None self.temperature = "froide" self.sel = False def remplir(self, quantite=1.5): """Remplit la casserole d'eau.""" self.eau = quantite print(f"Casserole remplie avec {quantite}L d'eau") def chauffer(self): """Chauffe l'eau jusqu'à ébullition.""" self.temperature = "chaude" print("Chauffage en cours...") self.temperature = "bouillante" print("L'eau bout !") def saler(self): """Ajoute du sel dans l'eau.""" self.sel = True print("Sel ajouté") class Pates: """Représente des pâtes à cuire.""" def __init__(self, type_pates="spaghetti", quantite=500): self.type = type_pates self.quantite = quantite # en grammes self.etat = "crues" self.temps_cuisson = 0 def cuire(self, casserole, duree=10): """ Fait cuire les pâtes dans une casserole. :param casserole: (Casserole) la casserole à utiliser :param duree: (int) temps de cuisson en minutes """ # Vérifications if casserole.eau is None: raise ValueError("La casserole doit contenir de l'eau !") if casserole.temperature != "bouillante": raise ValueError("L'eau doit être bouillante !") print(f"Ajout de {self.quantite}g de {self.type} dans la casserole") self.etat = "en cuisson" print(f"Cuisson pendant {duree} minutes...") self.temps_cuisson = duree self.etat = "cuites" print(f"Les {self.type} sont cuites !") def egoutter(self): """Égoutte les pâtes.""" if self.etat != "cuites": raise ValueError("Les pâtes doivent être cuites avant d'être égouttées !") print("Égouttage des pâtes...") self.etat = "prêtes" def __str__(self): return f"Pates({self.type}, {self.quantite}g, état={self.etat})" # Exécution def preparer_pates_oo(): """Prépare des pâtes en utilisant la POO.""" # Création des objets casserole = Casserole() pates = Pates("fusilli", 400) print(f"Début : {pates}") # Préparation de la casserole casserole.remplir(2.0) casserole.chauffer() casserole.saler() # Cuisson des pâtes pates.cuire(casserole, duree=12) pates.egoutter() print(f"Fin : {pates}") return pates resultat = preparer_pates_oo() ``` **Caractéristiques :** - Encapsulation (attributs et méthodes regroupés) - Objets avec état interne - Interactions entre objets (Pates et Casserole) - Méthodes qui modifient l'état de l'objet --- ## Tableau comparatif | Aspect | Impératif | Fonctionnel | Orienté Objet | |--------|-----------|-------------|---------------| | **État** | Variables modifiées | États immuables | Attributs d'objets | | **Données** | Variables simples | Dictionnaires/tuples | Objets | | **Actions** | Instructions séquentielles | Fonctions composées | Méthodes | | **Modification** | Sur place | Nouvel état retourné | Via méthodes | | **Réutilisabilité** | Faible | Moyenne | Forte | | **Testabilité** | Difficile | Facile | Moyenne | --- ## Bonus : Version lambda ```python # Version ultra-fonctionnelle avec lambdas et reduce import functools # Chaque étape est une lambda qui transforme l'état etapes = [ lambda e: {**e, "eau": 1.5}, lambda e: {**e, "temperature": "bouillante"}, lambda e: {**e, "sel": True}, lambda e: {**e, "pates": "en cuisson"}, lambda e: {**e, "temps": 10, "pates": "cuites"}, lambda e: {**e, "egouttees": True} ] # Composition avec reduce cuire_pates_lambda = lambda etat: functools.reduce( lambda e, f: f(e), etapes, etat ) # Exécution resultat = cuire_pates_lambda({"pates": "crues"}) print(resultat) # {'pates': 'cuites', 'eau': 1.5, 'temperature': 'bouillante', # 'sel': True, 'temps': 10, 'egouttees': True} ``` --- Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster Licence CC BY NC Licence Creative Commons
Ce cours est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International.