Corrigé Sujet N°10
- Analyse de Consommation d'Eau -
Vous pouvez télécharger les éléments suivants en cliquant sur les boutons associés :
Question 1
Écrire une fonction
total_conso qui prend en paramètres une liste de mesures et un jour (chaîne de caractères), et renvoie la consommation totale d'eau (chaude + froide) pour ce jour. La fonction renvoie None si aucune mesure n'existe pour ce jour.
Correction simple : On filtre les mesures du jour concerné, on additionne les consommations chaude et froide. On utilise un booléen pour savoir si au moins une mesure a été trouvée.
def total_conso(donnees, jour):
"""Retourne la consommation totale pour un jour, ou None si aucune mesure."""
total = 0
trouve = False
for mesure in donnees:
if mesure['jour'] == jour:
total += mesure['chaude'] + mesure['froide']
trouve = True
if not trouve:
return None
return total
# Tests
print(total_conso(donnees, "2025-02-04")) # >> 33
print(total_conso(donnees, "2025-12-25")) # >> None
Correction avancée : On construit d'abord la liste des consommations filtrées, puis on retourne
None si vide, ou la somme via sum(). C'est plus concis et sépare clairement le filtrage du calcul.
def total_conso(donnees, jour):
"""Version avancée avec compréhension de liste."""
consos = [m['chaude'] + m['froide'] for m in donnees if m['jour'] == jour]
return sum(consos) if consos else None
assert total_conso(donnees, "2025-02-04") == 33
assert total_conso(donnees, "2025-12-25") is None
assert total_conso(donnees, "2025-02-05") == 6
Question 2
Écrire une fonction
fuite_possible qui renvoie True si une fuite est possible (au moins 3 mesures consécutives entre 00:00 et 05:00 avec consommation totale non nulle), False sinon.
Correction simple : On parcourt les mesures du jour concerné entre 00:00 et 05:00, en maintenant un compteur de mesures non nulles consécutives. Dès qu'une mesure est nulle, on remet le compteur à zéro.
def fuite_possible(donnees, jour):
"""Retourne True si 3 mesures consécutives non nulles entre 00:00 et 05:00."""
consecutives = 0
heures_nuit = {"00:00", "01:00", "02:00", "03:00", "04:00", "05:00"}
for mesure in donnees:
if mesure['jour'] == jour and mesure['heure'] in heures_nuit:
conso = mesure['chaude'] + mesure['froide']
if conso > 0:
consecutives += 1
if consecutives >= 3:
return True
else:
consecutives = 0 # remise à zéro si une mesure est nulle
return False
# Tests
print(fuite_possible(donnees, "2025-02-04")) # >> False
print(fuite_possible(donnees, "2025-02-05")) # >> True (01:00, 02:00, 03:00 non nuls)
Correction avancée : On filtre d'abord les mesures pertinentes, puis on cherche 3 valeurs consécutives non nulles dans la liste résultante. On peut factoriser la détection de séquence dans une fonction générique.
def fuite_possible(donnees, jour):
"""Version avancée : filtrage puis recherche de séquence."""
heures_nuit = {"00:00", "01:00", "02:00", "03:00", "04:00", "05:00"}
mesures_nuit = [
m['chaude'] + m['froide']
for m in donnees
if m['jour'] == jour and m['heure'] in heures_nuit
]
# Recherche de 3 valeurs non nulles consécutives
count = 0
for v in mesures_nuit:
if v > 0:
count += 1
if count >= 3:
return True
else:
count = 0
return False
assert fuite_possible(donnees, "2025-02-04") == False
assert fuite_possible(donnees, "2025-02-05") == True
Question 3
La fonction
lissage_conso contient une erreur. Expliquer pourquoi la fonction produit un résultat incorrect avec la liste [10, 20, 30, 40, 50], et proposer une correction.
Identification du problème : Pour les éléments intermédiaires, la fonction calcule la moyenne sur 3 valeurs mais divise par
2 au lieu de 3. Par exemple, pour l'indice 1 (valeur 20) : (10 + 20 + 30) / 2 = 30 au lieu de (10 + 20 + 30) / 3 ≈ 20.
Correction simple : On remplace le diviseur
2 par 3 dans le cas intermédiaire.
def lissage_conso(valeurs):
"""Calcule une moyenne glissante corrigée sur les valeurs."""
lisse = []
for i in range(len(valeurs)):
if i == 0:
m = (valeurs[i] + valeurs[i + 1]) / 2
elif i == len(valeurs) - 1:
m = (valeurs[i - 1] + valeurs[i]) / 2
else:
m = (valeurs[i - 1] + valeurs[i] + valeurs[i + 1]) / 3 # CORRECTION : / 3
lisse.append(m)
return lisse
# Test
test = [10, 20, 30, 40, 50]
print(lissage_conso(test))
# >> [15.0, 20.0, 30.0, 40.0, 45.0]
Correction avancée : On peut tester la correction rigoureusement et rendre la taille de la fenêtre de lissage configurable pour plus de flexibilité.
def lissage_conso(valeurs):
"""Version corrigée avec assertions de test intégrées."""
lisse = []
for i in range(len(valeurs)):
if i == 0:
m = (valeurs[0] + valeurs[1]) / 2
elif i == len(valeurs) - 1:
m = (valeurs[-2] + valeurs[-1]) / 2
else:
m = (valeurs[i - 1] + valeurs[i] + valeurs[i + 1]) / 3
lisse.append(m)
return lisse
def test_lissage():
# Test basique
assert lissage_conso([10, 20, 30, 40, 50]) == [15.0, 20.0, 30.0, 40.0, 45.0]
# Vérifier que la liste retournée a la même taille
data = [5, 10, 15, 20]
assert len(lissage_conso(data)) == len(data)
# Liste homogène : lissage ne change rien
assert lissage_conso([5, 5, 5, 5]) == [5.0, 5.0, 5.0, 5.0]
print("Tous les tests lissage_conso sont passés.")
test_lissage()
Question 4
La fonction
lissage_conso gère le cas d'une liste à deux valeurs. Identifier un autre cas limite non pris en compte et proposer une solution.
Cas limite non géré : la liste vide. Si
valeurs = [], la boucle for i in range(len(valeurs)) ne s'exécute pas, donc la fonction retourne [] sans erreur — mais si l'on accède à valeurs[i + 1] ou valeurs[i - 1] pour une liste d'un seul élément, on obtient une IndexError. Le vrai cas limite non géré est la liste à un seul élément : l'indice 0 déclenche valeurs[1] qui n'existe pas.
Correction simple : On ajoute une garde en début de fonction pour traiter le cas de la liste vide et le cas de la liste à un seul élément.
def lissage_conso(valeurs):
"""Lissage corrigé avec gestion des cas limites."""
if len(valeurs) == 0:
return []
if len(valeurs) == 1:
return [float(valeurs[0])] # aucun voisin : on retourne la valeur elle-même
lisse = []
for i in range(len(valeurs)):
if i == 0:
m = (valeurs[0] + valeurs[1]) / 2
elif i == len(valeurs) - 1:
m = (valeurs[-2] + valeurs[-1]) / 2
else:
m = (valeurs[i - 1] + valeurs[i] + valeurs[i + 1]) / 3
lisse.append(m)
return lisse
# Tests des cas limites
assert lissage_conso([]) == []
assert lissage_conso([42]) == [42.0]
assert lissage_conso([10, 20]) == [15.0, 15.0]
print("Cas limites gérés correctement.")
Explication avancée : En programmation défensive, on doit toujours tester les cas aux bords : liste vide, liste unitaire, liste de deux éléments, et liste très longue. Ces cas sont souvent sources de bugs. Ici, la liste unitaire provoquait une
IndexError car l'indice 0 vérifie i == 0 (branche premier élément) et tente d'accéder à valeurs[1] qui n'existe pas.
© 2026 - Clément Legoubé