Épreuve pratique · 2026 · Sujet 12

Bac NSI pratique 2026 sujet 12 : Refuge de renards, objets et import CSV typé

Le refuge conserve les animaux dans une liste d’objets Renard. Chaque animal possède un identifiant entier, un nom, un poids flottant en kilogrammes et une date d’arrivée au format AAAA-MM-JJ. Le Refuge possède un nom, une adresse et liste_renards. Les données CSV utilisent le point-virgule. Le tableau ci-dessous reproduit l’extrait illustratif du PDF ; les noms du fichier réellement livré diffèrent, par exemple l’identifiant 101 y porte le nom Zorro. Les calculs du corrigé utilisent le fichier téléchargé.

Dans ce sujet

Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.

Application

Refuge de renards, objets et import CSV typé

Le refuge conserve les animaux dans une liste d’objets Renard. Chaque animal possède un identifiant entier, un nom, un poids flottant en kilogrammes et une date d’arrivée au format AAAA-MM-JJ. Le Refuge possède un nom, une adresse et liste_renards. Les données CSV utilisent le point-virgule. Le tableau ci-dessous reproduit l’extrait illustratif du PDF ; les noms du fichier réellement livré diffèrent, par exemple l’identifiant 101 y porte le nom Zorro. Les calculs du corrigé utilisent le fichier téléchargé.

idnom (extrait du PDF)poidsdate_arrivee
101Édgar6.52023-01-15
102César5.82023-02-10
103Gérard7.22023-03-05
104Sybille4.92024-11-20

Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.

Code fourni : gestion_refuge.py
import csv


class Renard:
    """
    Classe représentant un renard dans le refuge.
    Attributs : identifiant, nom, poids, date_arrivee.
    """

    def __init__(self, identifiant, nom, poids, date_arrivee):
        pass  # Question 1 à compléter

    def __str__(self):
        pass  # Question 2 à compléter


class Refuge:
    """
    Classe représentant le refuge contenant la liste des renards.
    """

    def __init__(self, nom, adresse):
        self.nom = nom
        self.adresse = adresse
        self.liste_renards = []

    def recueillir(self, un_renard):
        """
        Méthode d'ajout d'un renard au refuge.
        """
        self.liste_renards.append(un_renard)

    def lister_peu_corpulents(self):
        """
        Méthode qui renvoie une liste des Renards dont le poids est < 6.0 kg.
        """
        return [renard for renard in self.liste_renards if renard.poids < 6.0]

    def pourcentage_peu_corpulents(self):
        """
        Méthode qui renvoie le pourcentage des renards peu corpulents.
        """
        if len(self.liste_renards) == 0:
            return 0.0
        return len(self.lister_peu_corpulents()) / len(self.liste_renards) * 100

    def importer_donnees(self, nom_fichier):
        """
        Fonction qui importe les données des renards à partir d'un fichier CSV.
        """
        print(f"Tentative d'importation depuis {nom_fichier}...")
        with open(nom_fichier, 'r', encoding='utf-8') as f:
            lignes = csv.DictReader(f, delimiter=';')
            for ligne in lignes:
                renard = Renard(ligne['id'], ligne['nom'],
                                ligne['poids'], ligne['date_arrivee'])
                self.recueillir(renard)

Question 1

#

Écrire le constructeur __init__ de Renard.

Indice

Les valeurs doivent rester disponibles après la fin de l’appel.

Comprendre la correction
def __init__(self, identifiant, nom, poids, date_arrivee):
    self.identifiant = identifiant
    self.nom = nom
    self.poids = poids
    self.date_arrivee = date_arrivee

Chaque paramètre est stocké dans l’attribut homonyme de l’instance. Le constructeur ne doit pas utiliser de variable globale. Ici son contrat reçoit déjà les bons types ; l’import CSV sera responsable de convertir ses chaînes avant de créer l’objet.

Voir la question dans le sujet PDF, p. 2 (nouvel onglet)

Question 2

#

Écrire __str__ pour renvoyer exactement "Renard ID [id] - [Nom] (Arrivé le [date_arrivee])". Créer renard 1 : id 200, Oscar,5.1 kg, arrivé le 1 er janvier 2026 ; afficher son instance.

PythonDonner une représentation lisible à un objetÉcrivez votre solution et mettez-la à l’épreuve

Complétez __str__ dans la classe Renard. Renvoyez exactement la forme Renard ID 200 - Oscar (Arrivé le 2026-01-01), en utilisant les attributs de l’instance. Le constructeur est fourni. La méthode doit renvoyer une chaîne, pas afficher avec print. Ce défi isole la représentation d’objet, sans import CSV.

class Renard:
    def __init__(self, identifiant, nom, poids, date_arrivee):
        self.identifiant = identifiant
        self.nom = nom
        self.poids = poids
        self.date_arrivee = date_arrivee

    def __str__(self):
        # Complétez cette méthode
        pass

Les cas de test proposés :

  • Oscar, comme dans le sujet : La ponctuation et les espaces font partie de la forme demandée.
  • Une autre instance : Le résultat doit provenir des attributs, pas de l’exemple recopié.
  • La méthode renvoie du texte : Un print seul renvoie None et viole le contrat de __str__.
  • Changement de nom : La représentation reflète l’état actuel de l’objet sans changer son poids.
Indice

Une méthode spéciale __str__ doit retourner str.

Comprendre la correction
def __str__(self):
    return f'Renard ID {self.identifiant} - {self.nom} (Arrivé le {self.date_arrivee})'
renard1 = Renard(200, 'Oscar', 5.1, '2026-01-01')
print(renard1)
assert str(renard1) == 'Renard ID 200 - Oscar (Arrivé le 2026-01-01)'

La méthode doit renvoyer une chaîne. Un print dans __str__ renverrait implicitement None et ferait échouer print(renard 1). Les crochets de la description sont des emplacements à remplacer, pas des caractères à conserver.

Voir la question dans le sujet PDF, p. 2 (nouvel onglet)

Question 3

#

Identifier le défaut de importer_donnees concernant les poids et identifiants, corriger, puis créer SOS Goupil,12 rue de la Forêt et importer donnees_renards.csv.

Indice

Observer type(ligne["poids"]) avant la conversion.

Comprendre la correction

csv.DictReader renvoie les cellules sous forme de chaînes, même lorsqu’elles ressemblent à des nombres. Comparer un poids comme "5.8" à 6.0 provoque une erreur de type ; comparer ou additionner des identifiants textuels aurait aussi un autre sens. Les conversions doivent être explicites à la frontière d’entrée.

def importer_donnees(self, nom_fichier):
    with open(nom_fichier, 'r', encoding='utf-8', newline='') as fichier:
        for ligne in csv.DictReader(fichier, delimiter=';'):
            renard = Renard(int(ligne['id']), ligne['nom'],
                            float(ligne['poids']), ligne['date_arrivee'])
            self.recueillir(renard)
refuge = Refuge('SOS Goupil', '12 rue de la Forêt')
refuge.importer_donnees('donnees_renards.csv')
assert len(refuge.liste_renards) == 30
assert isinstance(refuge.liste_renards[0].identifiant, int)
assert isinstance(refuge.liste_renards[0].poids, float)

Le séparateur et l’encodage sont conservés. Importer deux fois sur la même instance ajouterait les animaux deux fois, car recueillir effectue append : recréer le refuge pour recommencer les tests, ou définir séparément une stratégie de remplacement/dédoublonnage.

L’import constitue une frontière entre deux représentations. Dans le fichier, chaque cellule est du texte ; dans le programme, l’identifiant et le poids ont un rôle numérique. Il est plus simple de convertir une seule fois à l’entrée que de disperser des conversions dans chaque fonction d’analyse. Après un import réussi, toutes les instances doivent respecter les mêmes types. Un affichage comme 6.5 ne permet pas de le prouver : la chaîne '6.5' et le flottant 6.5 se ressemblent à l’écran. D’où l’intérêt d’un test de type et d’un calcul réel après import.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 4

#

Exécuter lister_peu_corpulents et pourcentage_peu_corpulents. Justifier le résultat en affichant le nombre d’animaux de poids strictement inférieur à 6.0 kg et l’effectif total.

Comprendre la correction
peu_corpulents = refuge.lister_peu_corpulents()
print(len(peu_corpulents), len(refuge.liste_renards))
print(refuge.pourcentage_peu_corpulents())
for renard in peu_corpulents:
    print(renard, renard.poids)

Le fichier réel contient 30 renards, dont 15 ont un poids strictement inférieur à 6,0 kg. Le pourcentage vaut 15/30×100=50%. Un poids exactement 6,0 est exclu de cette catégorie. La méthode fournie renvoie 0.0 pour un refuge vide ; c’est sa convention de calcul, pas une proportion estimée sur des observations.

Le texte du CSV devient une donnéeUn atelier pour expérimenter

Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.

Lire les réponses et leurs explications
  1. Quel est le type initial de la cellule "5.8" lue par DictReader ?

    str. Le lecteur CSV fournit une chaîne.

  2. Un poids exactement 6.0 kg est-il retenu ?

    Non.. 6.0&lt;6.0 est faux.

Appuyez votre explication sur les valeurs et les conditions exactes du programme.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)
Du seuil au pourcentageUn atelier pour expérimenter

Modifiez le seuil d’analyse sur les trente poids réellement fournis. L’atelier garde la comparaison strictement inférieure ; le seuil demandé au bac reste 6 kg.

Lire le résultat de l’expérience initiale

15 renards sur 30, soit 50.0%.

Une valeur égale au seuil est exclue. Chaque ligne correspond à un poids du CSV, dans son ordre d’origine.

IdentifiantPoids (kg)Sous le seuil ?
1016.5Non
1025.8Oui
1037.2Non
1044.9Oui
1056.1Non
1065.5Oui
1077.8Non
1085.3Oui
1096.9Non
1104.5Oui
1113.2Oui
1127Non
1136.3Non
1145.7Oui
1156.6Non
1165.1Oui
1177.1Non
1185.9Oui
1196.8Non
1204.7Oui
1216.4Non
1225.6Oui
1237.3Non
1244.8Oui
1256.2Non
1265Oui
1277.4Non
1284.6Oui
1296.7Non
1305.2Oui

La conversion de type conditionne la validité de toutes les analyses suivantes.

Revoir les notions de cet exercice

Du sujet à la méthode

Votre prochaine séance de révision

  • Tester les types à l’import, pas seulement l’apparence de l’affichage.
  • Un seuil strict se vérifie avec une valeur exactement égale au seuil.

Retrouver ces notions dans d’autres sujets

Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027

Énoncé : sujet 26_BCG_NSI_12 (PDF). Corrigé et explications pédagogiques proposés par Sofien.