# -*- coding: utf-8 -*- """ Corrigé Python - Bac NSI 2026 - Épreuve pratique - Sujet 5 Thème : empreinte carbone Ce fichier propose une correction concise des fonctions demandées. Il peut être ouvert directement dans un navigateur ou exécuté avec Python. """ from __future__ import annotations import json from pathlib import Path from typing import Any # ----------------------------------------------------------------------------- # Fonctions données dans le sujet # ----------------------------------------------------------------------------- def chargement_json(nom_fichier: str) -> dict[str, Any]: """ Charge le contenu d'un fichier JSON et renvoie un dictionnaire Python. """ with open(nom_fichier, "r", encoding="utf-8") as curseur: return json.load(curseur) def est_dictionnaire(objet: Any) -> bool: """ Renvoie True si l'objet est un dictionnaire, False sinon. """ return isinstance(objet, dict) # ----------------------------------------------------------------------------- # Question 1 # ----------------------------------------------------------------------------- def total_simple(empreinte: dict[str, int | float]) -> int | float: """ Renvoie la somme des empreintes carbone d'un dictionnaire simple. Le dictionnaire associe directement chaque catégorie à une valeur numérique. """ total = 0 for valeur in empreinte.values(): total += valeur return total # ----------------------------------------------------------------------------- # Question 2 # ----------------------------------------------------------------------------- def total_rec(empreinte: dict[str, Any]) -> int | float: """ Renvoie la somme des valeurs numériques présentes dans un dictionnaire imbriqué. Si une valeur est elle-même un dictionnaire, on additionne récursivement toutes les valeurs numériques qu'il contient. """ total = 0 for valeur in empreinte.values(): if est_dictionnaire(valeur): total += total_rec(valeur) else: total += valeur return total # ----------------------------------------------------------------------------- # Questions 3 et 4 # ----------------------------------------------------------------------------- def alerte_valeur_aberrante(empreinte: dict[str, Any], limite: int | float) -> bool: """ Renvoie True si au moins une valeur numérique dépasse strictement la limite. Erreur à éviter : il ne faut pas renvoyer immédiatement le résultat du premier sous-dictionnaire rencontré. S'il ne contient aucune valeur aberrante, il faut continuer le parcours des autres catégories. """ for valeur in empreinte.values(): if est_dictionnaire(valeur): if alerte_valeur_aberrante(valeur, limite): return True else: if valeur > limite: return True return False # ----------------------------------------------------------------------------- # Tests # ----------------------------------------------------------------------------- def test_total_simple() -> None: """Teste le calcul d'une somme dans un dictionnaire non imbriqué.""" empreinte = {"Logement": 2660, "Alimentation": 1500, "Transport": 708} assert total_simple(empreinte) == 4868 def test_total_rec() -> None: """Teste le calcul récursif dans des dictionnaires imbriqués.""" test_dico1 = {"a": 1, "d": 2} assert total_rec(test_dico1) == 3 test_dico2 = {"a": {"b": 1, "c": 2}, "d": {"e": 3}} assert total_rec(test_dico2) == 6 test_dico3 = { "Logement": { "Energie": {"Electricité": 206, "Chauffage individuel": 1500}, "Construction": 650, }, "Transport": {"Train": 14}, } assert total_rec(test_dico3) == 2370 def test_alerte_valeur_aberrante() -> None: """Teste les principaux cas limites de la fonction d'alerte.""" # Cas 1 : aucune valeur ne dépasse la limite. assert alerte_valeur_aberrante({"a": 10, "b": 20}, 100) is False # Cas 2 : une valeur simple dépasse la limite. assert alerte_valeur_aberrante({"a": 10, "b": 150}, 100) is True # Cas 3 : la valeur aberrante est dans un dictionnaire imbriqué. empreinte = {"a": {"b": 10}, "c": {"d": 1500}} assert alerte_valeur_aberrante(empreinte, 1000) is True # Cas 4 : le premier sous-dictionnaire ne contient rien d'aberrant, # mais le second oui. C'est le cas qui révèle l'erreur de conception. empreinte = {"premier": {"a": 10}, "second": {"b": 1500}} assert alerte_valeur_aberrante(empreinte, 1000) is True # ----------------------------------------------------------------------------- # Lancement facultatif # ----------------------------------------------------------------------------- if __name__ == "__main__": test_total_simple() test_total_rec() test_alerte_valeur_aberrante() print("Tous les tests du sujet 5 sont réussis.") # Si les fichiers JSON du sujet sont présents dans le même dossier que ce # corrigé, on affiche aussi les totaux de l'empreinte carbone d'Ada. dossier = Path(__file__).parent fichier_agrege = dossier / "empreinte_ada_agr.json" fichier_complet = dossier / "empreinte_ada.json" if fichier_agrege.exists(): empreinte_agregee = chargement_json(str(fichier_agrege)) print("Total simple :", total_simple(empreinte_agregee)) if fichier_complet.exists(): empreinte_complete = chargement_json(str(fichier_complet)) print("Total récursif :", total_rec(empreinte_complete)) print("Alerte limite 1000 :", alerte_valeur_aberrante(empreinte_complete, 1000))