Maths & NSI

Baccalauréat — Épreuve pratique — 2026 — NSI

Épreuve pratique NSI 2026 — Sujet 17 : budget d'un club de handball

Sujet

Épreuve pratique de NSI, session 2026 — sujet n°17 de la banque nationale. Durée : 1 heure, sur ordinateur. Le candidat dispose de l'énoncé et de fichiers de code et de données ; il agit en autonomie et, aux « appels professeur » indiqués, présente son travail à l'examinateur ou le sollicite en cas de difficulté.

Budget d'un club de handball

Un club de handball professionnel souhaite mieux comprendre et gérer ses dépenses et recettes annuelles. Les dirigeants veulent identifier les postes de dépenses les plus importants et s'assurer de l'exactitude de leur solde budgétaire de fin d'année.

On dispose de jeux de données sous forme de fichiers CSV représentant les mouvements budgétaires du club. Chaque mouvement est décrit par un enregistrement comportant les attributs suivants :

  • 'type' : chaîne de caractères dont les valeurs possibles sont 'dépense' ou 'recette' ;
  • 'catégorie' : chaîne de caractères dont les valeurs possibles sont 'subventions', 'sponsoring', 'billetterie', 'marketing', 'salaires', 'déplacements', 'fonctionnement', 'cotisations' ou 'autres_charges' ;
  • 'montant' : nombre flottant positif représentant la somme en euros ;
  • 'mois' : nombre entier compris entre 1 et 12.

Une fois chargés par le script analyse_budget.py, ces jeux de données donnent une liste de dictionnaires mouvements. Deux jeux de données sont fournis :

  • un jeu de test défini directement dans le code dans la variable mouvements_test ;
  • un jeu complet budget_complet.csv de plus de 2 000 mouvements.

Le fichier analyse_budget.py contient plusieurs fonctions d'analyse que le sujet vise à compléter.

Question 1. Écrire la fonction total_par_type(mouvements, type_mouvement) qui prend en paramètres une liste de mouvements et une chaîne de caractères (parmi 'dépense' ou 'recette'). Cette fonction doit renvoyer la somme totale des montants correspondant à ce type précis. La fonction renverra 0 si aucun mouvement ne correspond. Créer ensuite une fonction test_total() contenant au moins deux assertions pour valider le bon fonctionnement de votre code sur le jeu de données mouvements_test (par exemple, le total des recettes attendu est de 2300.0).

Appel professeur — Appeler le professeur pour lui présenter votre réponse ou en cas de difficulté.

La fonction solde_annuel(mouvements), déjà codée dans le fichier fourni, est censée calculer le bilan financier de l'année en faisant la somme des soldes de chaque mois (recettes totales moins dépenses totales). Si le solde annuel est positif, le club dégage des bénéfices. S'il est négatif, le club est en déficit.

Question 2. Calculer manuellement le solde annuel attendu pour la liste mouvements_test. Écrire ensuite une fonction test_solde_annuel() contenant une assertion qui vérifie que la fonction solde_annuel(mouvements_test) renvoie bien ce résultat théorique. Exécuter ce test.

L'exécution du test précédent lève une erreur : le résultat renvoyé par la fonction solde_annuel ne correspond pas à la réalité comptable.

Question 3. Analyser le code de la fonction solde_annuel pour identifier la source de cette erreur logique, expliquer pourquoi certains mouvements ont été ignorés, puis proposer une correction. Appliquer ensuite votre fonction corrigée sur le fichier budget_complet.csv pour annoncer le véritable solde du club au professeur.

Appel professeur — Appeler le professeur pour lui présenter votre réponse ou en cas de difficulté.

Fichiers fournis

Le dossier comporte une version PDF de l'énoncé, le code source à analyser et compléter analyse_budget.py et le jeu de données complet budget_complet.csv (2 026 mouvements).

analyse_budget.py

import csv
 
 
def lire_mouvements_depuis_csv(nom_fichier_csv):
    """
    Lit les données d'un fichier CSV et les retourne en liste de dictionnaires.
    Les colonnes 'montant' et 'mois' sont converties respectivement en flottant et en entier.
    """
    mouvements_csv = []
    try:
        with open(nom_fichier_csv, mode='r', newline='', encoding='utf-8') as fichier_csv:
            lecteur_csv = csv.DictReader(fichier_csv)
            for ligne in lecteur_csv:
                ligne['montant'] = float(ligne['montant'])
                ligne['mois'] = int(ligne['mois'])
                mouvements_csv.append(ligne)
        return mouvements_csv
    except FileNotFoundError:
        print(f"Erreur : Le fichier '{nom_fichier_csv}' est introuvable.")
        return []
 
 
mouvements_test = [
    {'type': 'recette', 'catégorie': 'cotisations', 'montant': 1200.0, 'mois': 1},
    {'type': 'recette', 'catégorie': 'billetterie', 'montant': 300.0, 'mois': 6},
    {'type': 'dépense', 'catégorie': 'fonctionnement', 'montant': 450.0, 'mois': 6},
    {'type': 'dépense', 'catégorie': 'déplacements', 'montant': 200.0, 'mois': 12},
    {'type': 'dépense', 'catégorie': 'salaires', 'montant': 1500.0, 'mois': 12},
    {'type': 'recette', 'catégorie': 'subventions', 'montant': 800.0, 'mois': 12}
]
 
#############################################################################
# Écrire ci-dessous la fonction total_par_type et ses tests (Question 1)    #
#############################################################################
 
 
#############################################################################
# Fonctions de calcul du solde (Questions 2 et 3)                           #
#############################################################################
 
def solde_mensuel(mouvements, mois):
    """
    Calcule le solde pour un mois donné (recettes - dépenses).
    """
    total_recettes = 0
    total_depenses = 0
 
    for m in mouvements:
        if m['mois'] == mois:
            if m['type'] == 'recette':
                total_recettes += m['montant']
            else:
                total_depenses += m['montant']
 
    return total_recettes - total_depenses
 
 
def solde_annuel(mouvements):
    """
    Calcule le solde annuel en additionnant les soldes de chaque mois.
    """
    total = 0
    # Parcourt les mois de l'année pour cumuler le bilan
    for m in range(1, 12):
        total = total + solde_mensuel(mouvements, m)
 
    return total
 
 
#############################################################################
# Écrire ci-dessous la fonction test_solde_annuel (Question 2)              #
#############################################################################
 
 
#############################################################################
# Programme principal pour analyser le fichier complet                      #
#############################################################################
 
# mouvements_complets = lire_mouvements_depuis_csv("budget_complet.csv")
# print("Le solde annuel sur le fichier complet est de :", solde_annuel(mouvements_complets))

budget_complet.csv (début du fichier)

type,catégorie,montant,mois
dépense,autres_charges,269.87,1
dépense,autres_charges,165.32,1
dépense,autres_charges,320.95,1
dépense,autres_charges,259.87,1
dépense,autres_charges,100.52,1
...

Corrigé

Corrigé réservé aux abonnés Premium.

Créez un compte gratuit : votre première correction est offerte.

Sujet officiel de la banque nationale de sujets 2026 de l'épreuve pratique de NSI (ministère de l'Éducation nationale, sujets.examens-concours.gouv.fr). Corrigé rédigé pour ce site.