← Bibliothèque · PRO · Réussir tes TP Python
0/0 ⬇
Collection « Challenges » · Apprendre à coder en Python · Étudiants · Pro

Réussir tes TP Python — 4 semaines pour rendre un TP d'analyse de données que tu comprends

En quatre semaines, tu réussis tes TP : tu écris tes fonctions, tu structures tes données, tu lis et écris des fichiers, tu traces tes graphiques et tu versionnes ton travail. Ta boîte à outils d'étudiant est prête.

20 épisodes · 4 semaines1 épisode par jour, du lundi au vendrediThonny, VS Code ou navigateur≈ 20 min / épisode
BOOST · 5 JOURSMaîtriser les bases et écrire un premier script utile pour tes cours.
PRO · 20 JOURSFonctions, données, fichiers, graphiques et Git pour réussir tes TP.
MASTER · 4 MOISConcevoir un projet testé et publié, raisonner sur les algorithmes, aider tes pairs.
Le fil rouge. Yanis, 18 ans, en 1re année de licence de sciences de la vie (personnage fictif), a terminé le Boost. Il a quatre semaines pour rendre un TP d'analyse de données : des mesures de croissance de plantules sous trois éclairages. Cette fois, il veut comprendre chaque ligne de ce qu'il rend.
Chaque épisode = un scénario, une notion ou une méthode, ce que disent les sources, des idées reçues, un quiz, ton kit et ton journal. Le vendredi, un bilan et un badge.
Tes données restent chez toi. Ta progression et ton journal sont enregistrés seulement dans ce navigateur. Les données du TP sont inventées ; n'utilise jamais de données personnelles réelles.
Règle d'or. Un code que tu ne comprends pas, tu ne le lances pas… et tu ne le rends pas en TP.
Ce que tu sais déjàTu écris un algorithme puis le programme, avec des variables, des types et des calculs (Boost, épisode 1). Tu lances un script et tu lis une erreur en 3 questions (Boost, épisode 2). Tu décides avec if / elif / else et tu répètes avec for et while (Boost, épisode 3). Tu construis un programme pas à pas, testé sur un cas calculé à la main (Boost, épisode 4), et tu as écrit ton calculateur de moyennes (Boost, épisode 5). Tu démarres ici sans avoir suivi le Boost ? Le kit de rattrapage est en fin de livre.
ARC 1 · SEMAINE 1

Écrire des fonctions

Cette semaine, tu crées tes propres fonctions, tu mets en forme tes résultats et tu apprends à chasser les bugs avec méthode. Vendredi, les fonctions de calcul de ton TP sont prêtes et vérifiées.

01
S1 · LUNDI · Comprendre

Écrire ses propres fonctions

Définir une fonction, lui donner des paramètres, récupérer une valeur renvoyée, et comprendre où vivent ses variables.

⏱ 15 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Lundi, 8 h

Présentation du TP. L'enseignante distribue le script d'une ancienne promotion : la même conversion de centimètres en millimètres y est recopiée onze fois. « Et la formule est fausse à un endroit. Lequel ? Bon courage. » Yanis compte les copies. Awa, sa binôme, soupire : « Il fallait l'écrire une fois, et lui donner un nom. »

[2]Concept

La fonction : une tâche, un nom

Une fonction est un morceau de code auquel on donne un nom, pour s'en servir autant de fois qu'on veut. Tu en utilises déjà : print, input, round. Maintenant, tu écris les tiennes.

Code
def cm_vers_mm(taille_cm):
    """Convertit une taille en centimètres en millimètres."""
    return taille_cm * 10


print(cm_vers_mm(2.5))
print(cm_vers_mm(12))

Affiche 25.0, puis 120.

  • def définit la fonction : son nom, puis ses paramètres entre parenthèses, puis deux-points. Le corps est décalé de 4 espaces.
  • La première ligne entre triples guillemets est la docstring : une phrase qui dit ce que fait la fonction.
  • return renvoie une valeur à celui qui a appelé la fonction, et termine la fonction.
  • cm_vers_mm(2.5) appelle la fonction : le paramètre taille_cm reçoit l'argument 2.5.
  • Une fonction définie n'est exécutée que lorsqu'on l'appelle. On la nomme par un verbe ou une action (convertir, cm_vers_mm), en minuscules avec des _.

print ou return ? Ce n'est pas pareil :

Code
def double_affiche(x):
    print(x * 2)


def double_renvoie(x):
    return x * 2


a = double_affiche(5)
b = double_renvoie(5)
print(a, b)

Affiche 10, puis None 10. double_affiche montre 10 à l'écran mais ne renvoie rien : sans return, une fonction renvoie None (« rien »). double_renvoie donne 10 au programme, qui peut le ranger, le calculer, le réutiliser. Dans un TP, les fonctions de calcul renvoient ; seul le programme principal affiche.

Une valeur par défaut.

Code
def arrondir(valeur, chiffres=2):
    """Arrondit une valeur, à 2 chiffres après la virgule par défaut."""
    return round(valeur, chiffres)


print(arrondir(13.08333))
print(arrondir(13.08333, 1))

Affiche 13.08, puis 13.1. Si on ne donne pas chiffres, il vaut 2.

Où vivent les variables (la portée).

Code
def calculer_total(a, b):
    total = a + b
    return total


resultat = calculer_total(3, 4)
print(resultat)
print(total)

Affiche 7, puis s'arrête : NameError: name 'total' is not defined. La variable total est locale : elle n'existe que pendant l'exécution de la fonction. Pour récupérer son contenu, on utilise ce que la fonction renvoie (resultat).

Machine à fonction · def cm_vers_mm(taille_cm): return taille_cm * 10
Choisis une entrée pour voir ce que la machine fait.

Résultats vérifiés avec Python : un entier reste un entier (12 * 10 donne 120), un nombre à virgule reste à virgule (2.5 * 10 donne 25.0).

[3]Recherche

Ce que disent les sources

  • Tutoriel officiel de Python — Le mot-clé def introduit une définition de fonction ; il est suivi du nom de la fonction et de la liste de ses paramètres entre parenthèses ; le corps commence à la ligne suivante et doit être indenté. return sans expression, ou la fin de la fonction, renvoie None [1].
  • Tutoriel officiel de Python — L'exécution d'une fonction crée un espace de noms local : toutes les affectations faites dans la fonction y rangent leurs valeurs. On peut donner une valeur par défaut à des paramètres ; elle n'est évaluée qu'une seule fois, à la définition [1].
  • PEP 257 — Une docstring est une chaîne placée en première instruction d'une fonction ; sa première ligne doit être un résumé court [2].
[4]Mythes
« print et return, c'est pareil. »
print montre une valeur à l'écran ; return la donne au programme. Une fonction qui affiche sans renvoyer renvoie None.
« Une variable créée dans une fonction existe partout. »
elle est locale et disparaît à la fin de l'appel ; on récupère le résultat par return.
« Les fonctions, c'est pour les gros programmes. »
dès qu'un calcul sert deux fois, une fonction évite de recopier… et de recopier une erreur.
[5]Quiz

1. Qu'affiche print(f(3) * 2) si f(x) renvoie x + 1 ?

f(3) vaut 4, et 4 × 2 = 8 (sortie vérifiée).

2. La fonction g(x) contient seulement print(x). Qu'affiche r = g(2) puis print(r) ?

l'appel affiche 2, mais g ne renvoie rien : r vaut None (sortie vérifiée).

3. def h(a, b=10): return a - b. Qu'affiche print(h(15), h(15, 5)) ?

sans deuxième argument, b vaut 10 : 15 − 10 = 5 ; avec 5 : 15 − 5 = 10 (sortie vérifiée).
[6]Kit

🎒 Ton kit — Épisode 1

15 min

Exercice : prédire, puis écrire ta première fonction de TP

  1. Prédis ce qu'affiche ce programme, puis vérifie :
Code
def k(n):
    n = n * 2
    return n


n = 3
print(k(n), n)
  1. Écris une fonction moyenne_ponderee(note1, coef1, note2, coef2) qui renvoie la moyenne pondérée de deux notes, avec une docstring. Vérifie-la avec le cas calculé à la main : 12 (coef 2) et 15,5 (coef 3) → 14,1.

Corrigé (sorties réelles) : le programme affiche 6 3. Le n de la fonction est local : le doubler ne change pas le n du programme. Et moyenne_ponderee(12, 2, 15.5, 3) renvoie 14.1.

Code à copier
def moyenne_ponderee(note1, coef1, note2, coef2):
    """Renvoie la moyenne pondérée de deux notes."""
    return (note1 * coef1 + note2 * coef2) / (coef1 + coef2)


print(moyenne_ponderee(12, 2, 15.5, 3))

Checklist

  • Je sais définir et appeler une fonction.
  • Je fais la différence entre print et return.
  • Je sais qu'une variable créée dans une fonction est locale.
Vigilancedéfinis une fonction avant la ligne qui l'appelle ; sinon, Python s'arrête avec une NameError.
[7]Journal

✍️ Journal de bord

Dans tes TP ou tes cours, quel calcul aurais-tu dû écrire une seule fois, sous forme de fonction ?

[8]Sources
  1. Python Software Foundation, Tutoriel Python — 4. D'autres outils de contrôle de flux, 4.8 « Définir des fonctions » et 4.9 (valeurs par défaut, chaînes de documentation), consulté le 30/10/2026.
  2. D. Goodger, G. van Rossum, PEP 257 – Docstring Conventions, consulté le 30/10/2026.
02
S1 · MARDI · Pratiquer

Ranger ton calculateur en fonctions

Une tâche, une fonction, un test : découper un script existant et vérifier chaque pièce.

⏱ 20 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Mardi, 18 h

Pour le TP, Yanis a besoin d'une saisie contrôlée et d'une mention, comme dans son calculateur du Boost. Il s'apprête à copier-coller les 25 lignes. Puis il se souvient de la phrase de l'enseignante : « Une erreur, onze corrections. » Il décide de ranger son calculateur en fonctions, et de vérifier chacune.

[2]Méthode

« Une tâche, une fonction, un test »

Rappel : définir une fonction, return (voir épisode 1).

  1. Repérer les tâches dans le script : saisir une note valide, saisir un coefficient valide, choisir une mention.
  2. Une fonction par tâche, nommée par une action, avec une docstring. Elle renvoie son résultat ; elle n'affiche que si c'est son rôle (une saisie).
  3. Tester chaque fonction seule sur des cas connus. assert vérifie qu'une condition est vraie, et arrête le programme si elle est fausse.
  4. Assembler : le programme principal enchaîne les appels.
Code
def mention(moyenne):
    """Renvoie la mention correspondant à une moyenne sur 20."""
    if moyenne >= 16:
        return "Mention très bien"
    elif moyenne >= 14:
        return "Mention bien"
    elif moyenne >= 12:
        return "Mention assez bien"
    return "Pas de mention"


assert mention(16) == "Mention très bien"
assert mention(15.99) == "Mention bien"
assert mention(12) == "Mention assez bien"
assert mention(11.99) == "Pas de mention"
print("Tests de mention : OK")

Affiche Tests de mention : OK. On teste pile sur chaque seuil et juste en dessous. Chaque return termine la fonction : pas besoin d'else pour le dernier cas.

Si une vérification échoue, par exemple assert mention(14) == "Mention assez bien", Python s'arrête :

Message d'erreur
Traceback (most recent call last): File "e2_assert_faux.py", line 13, in <module> assert mention(14) == "Mention assez bien" AssertionError

Soit la fonction est fausse, soit le test : ici, c'est le test (14 donne « bien »).

Le calculateur rangé (code à copier) :

Code
def saisir_note():
    """Demande une note jusqu'à ce qu'elle soit entre 0 et 20, puis la renvoie."""
    note = float(input("  Note sur 20 (avec un point) : "))
    while note < 0 or note > 20:
        print("  Une note est comprise entre 0 et 20.")
        note = float(input("  Note sur 20 (avec un point) : "))
    return note


def saisir_coef():
    """Demande un coefficient jusqu'à ce qu'il soit positif, puis le renvoie."""
    coef = float(input("  Coefficient : "))
    while coef <= 0:
        print("  Un coefficient est un nombre positif.")
        coef = float(input("  Coefficient : "))
    return coef


def mention(moyenne):
    """Renvoie la mention correspondant à une moyenne sur 20."""
    if moyenne >= 16:
        return "Mention très bien"
    elif moyenne >= 14:
        return "Mention bien"
    elif moyenne >= 12:
        return "Mention assez bien"
    return "Pas de mention"


nb_matieres = int(input("Nombre de matières : "))
total = 0
somme_coefs = 0
for i in range(nb_matieres):
    print("Matière", i + 1)
    note = saisir_note()
    coef = saisir_coef()
    total = total + note * coef
    somme_coefs = somme_coefs + coef
moyenne = round(total / somme_coefs, 2)
print("Moyenne :", moyenne, "sur 20")
print(mention(moyenne))

Essai réel avec le cas de référence du Boost (12 coef 2, 15,5 coef 3, 8 coef 1) : Moyenne : 13.08 sur 20, puis Mention assez bien. Et avec une note de 25 puis 14, un coefficient de 0 puis 1 : les deux saisies refusées sont redemandées, puis Moyenne : 14.0 sur 20 et Mention bien.

[3]Pourquoi ça marche

Une fonction testée seule est une pièce sur laquelle on peut compter : si le calculateur se trompe, on sait que ce n'est pas mention. Le programme principal, lui, se lit comme une liste d'étapes : saisir, accumuler, calculer, afficher. Et le jour où le seuil d'une mention change, il y a un seul endroit à corriger.

À retenirune tâche, une fonction, un test ; on teste pile sur les seuils et juste en dessous.
[4]Entraînement

Bon réflexe ou piège ?

Ma fonction de calcul affiche son résultat avec print au lieu de le renvoyer.
le programme ne peut pas réutiliser le résultat (il reçoit None).
J'écris une fonction qui saisit, calcule et affiche tout à la fois.
impossible de la tester ou de la réutiliser morceau par morceau.
Je vérifie mention pile sur 16, 14 et 12, et juste en dessous.
c'est aux seuils que se cachent les erreurs (> au lieu de >=).
J'appelle mes fonctions f1, f2, f3.
dans une semaine, ni toi ni ton binôme ne saurez ce qu'elles font.
Je teste chaque fonction avant d'assembler le programme.
quand tout est assemblé, une erreur peut venir de partout.
[5]Quiz

1. Que renvoie une fonction de mention écrite avec print(...) au lieu de return ... ?

elle affiche la mention mais ne renvoie rien ; resultat = mention(13) vaut None (sortie vérifiée : Résultat : None).

2. Que fait assert mention(12) == "Mention assez bien" si la fonction est juste ?

assert ne dit rien quand la condition est vraie ; il arrête le programme seulement si elle est fausse.

3. Pourquoi tester mention(15.99) en plus de mention(16) ?

un > à la place de >=, ou l'inverse, ne se voit qu'aux seuils.
[6]Kit

🎒 Ton kit — Épisode 2

20 min

Exercice : ton calculateur en 3 fonctions

  1. Écris saisir_note, saisir_coef et mention, chacune avec sa docstring.
  2. Vérifie mention avec 4 assert (pile sur les seuils et juste en dessous).
  3. Assemble le calculateur et teste-le avec le cas de référence du Boost.
  4. Bonus : écris une fonction appreciation(moyenne) (« à retravailler », « correct », « très bon ») et ses vérifications.

Code à copier : le calculateur rangé ci-dessus.

Checklist

  • Chaque tâche a sa fonction, nommée et documentée.
  • mention passe 4 vérifications.
  • Le calculateur assemblé donne le résultat attendu.
Vigilanceune fonction que tu rends dans un TP noté doit être la tienne, ou son origine doit être déclarée.
[7]Journal

✍️ Journal de bord

Laquelle de tes fonctions a été la plus difficile à nommer ? Qu'est-ce que cela dit de ce qu'elle fait ?

[8]Sources
  1. Python Software Foundation, Référence du langage — L'instruction assert, consulté le 30/10/2026.
  2. Sorties du calculateur et des vérifications : exécutions réelles sous Python 3.12.13 et 3.15.0 (journal de test de ce livre), le 30/10/2026.
03
S1 · MERCREDI · Comprendre

Le texte et les f-strings

Découper, nettoyer et comparer du texte, puis afficher des résultats propres avec les f-strings.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Mercredi, 14 h

Dans le tableur de la salle de TP, les noms des éclairages ont été tapés par six étudiants différents : " Lumière-Bleue ", "lumière bleue", "LUMIÈRE BLEUE"… Pour Python, ce sont trois éclairages différents. Et les moyennes de Yanis s'affichent avec quinze décimales : 13.083333333333334 mm. Son enseignante a été claire : « Deux décimales, l'unité, et des colonnes alignées. »

[2]Concept

Les chaînes de caractères et les f-strings

Une chaîne est une suite de caractères numérotés à partir de 0.

Code
nom = " Lumière-Bleue "
print(len(nom))
propre = nom.strip().lower()
print(propre)
print(propre[0], propre[-5:], propre[:7])
print(propre.replace("-", " "))
print("bleue" in propre)
print(nom)

Affiche :

Ce que tu vois
15 lumière-bleue l bleue lumière lumière bleue True Lumière-Bleue
ÉcritureCe qu'elle donne
len(nom)le nombre de caractères (espaces compris)
nom[0], nom[-1]le premier, le dernier caractère
nom[:7], nom[-5:]une tranche : les 7 premiers, les 5 derniers caractères
.strip()une copie sans les espaces au début et à la fin
.lower(), .upper()une copie en minuscules, en majuscules
.replace("-", " ")une copie où chaque - est remplacé par une espace
.startswith("lum")True si la chaîne commence ainsi
"bleue" in nomTrue si le texte est présent
.split(";")découpe la chaîne en morceaux : "12,5;14;9".split(";") donne ['12,5', '14', '9'], une liste (semaine 2)

Une chaîne ne se modifie pas. La dernière ligne affiche toujours " Lumière-Bleue " : .strip() et .lower() fabriquent une nouvelle chaîne, qu'il faut ranger dans une variable (propre = …). Écrire nom.upper() seul ne change rien à nom.

La virgule décimale. Tu as vu au Boost que float("12,5") s'arrête sur une ValueError (voir Boost, épisode 5). Avec replace, tu peux la convertir : float("12,5".replace(",", ".")) donne 12.5.

Les f-strings. Une chaîne précédée de f remplace ce qui est entre accolades par sa valeur. Après :, on précise le format.

Code
moyenne = 13.083333333333334
eclairage = "bleue"
print(f"Lumière {eclairage} : {moyenne:.2f} mm")
print(f"{'Éclairage':<10}{'Moyenne':>10}")
print(f"{'bleue':<10}{13.0833:>10.2f}")
print(f"{'rouge':<10}{9.5:>10.2f}")
print(f"{moyenne=}")

Affiche :

Ce que tu vois
Lumière bleue : 13.08 mm Éclairage Moyenne bleue 13.08 rouge 9.50 moyenne=13.083333333333334
  • :.2f : 2 chiffres après la virgule (un point, en Python) ;
  • :<10 : aligné à gauche sur 10 caractères ; :>10 : à droite ; :>10.2f : les deux ;
  • {moyenne=} affiche le nom et la valeur : très pratique pour déboguer (épisode 4).

round ou :.2f ? round(14.1, 2) renvoie le nombre 14.1 ; f"{14.1:.2f}" renvoie le texte "14.10". On calcule avec des nombres, et on formate seulement au moment d'afficher.

Générateur · une f-string de résultat
Code obtenu
Ce qui s'afficherait

L'arrondi suit celui de Python : à égalité parfaite, vers le chiffre pair (f"{0.125:.2f}" donne 0.12).

[3]Recherche

Ce que disent les sources

  • Tutoriel officiel de Python — Les chaînes peuvent être indexées (le premier caractère a l'indice 0, les indices négatifs partent de la fin) et découpées en tranches ; elles sont immuables : on ne peut pas modifier un caractère d'une chaîne existante [1].
  • Documentation officielle de Python — Dans le mini-langage de format, le type f affiche un nombre en virgule fixe avec exactement le nombre de chiffres demandé après la virgule (6 par défaut) ; <, > et ^ alignent à gauche, à droite ou au centre dans la largeur indiquée [2].
  • Nouveautés de Python 3.8 — Le spécificateur = a été ajouté aux f-strings : f'{expr=}' affiche le texte de l'expression, le signe égal et sa valeur, pour l'auto-documentation et le débogage [3]. Les exemples de ce livre fonctionnent avec Python 3.12 et plus.
[4]Mythes
« .lower() met la variable en minuscules. »
il renvoie une nouvelle chaîne ; la variable ne change que si on écrit nom = nom.lower() (sortie vérifiée : bleue, puis BLEUE après réaffectation).
« Arrondir avec round et formater avec :.2f, c'est pareil. »
round renvoie un nombre (14.1), :.2f un texte ("14.10").
« Les f-strings sont un gadget d'affichage. »
elles produisent des chaînes qu'on peut ranger, comparer, écrire dans un fichier ; et {x=} est un outil de débogage.
[5]Quiz

1. Que vaut "plantule"[-3:] ?

une tranche avec -3: garde les 3 derniers caractères.

2. Qu'affiche print(f"{9.5:.2f}") ?

.2f impose exactement 2 chiffres après la virgule.

3. Après nom = "bleue" puis nom.upper(), que vaut nom ?

la chaîne ne change pas ; nom.upper() a fabriqué une copie qui n'a été rangée nulle part (sortie vérifiée).
[6]Kit

🎒 Ton kit — Épisode 3

20 min

Exercice : nettoyer les noms, aligner les résultats

  1. Écris la fonction nettoyer_nom(texte) ci-dessous et vérifie qu'elle donne le même résultat pour " Lumière-Bleue " et "LUMIÈRE BLEUE".
  2. Affiche un petit tableau de 3 éclairages et de leurs moyennes, aligné, avec 2 décimales et l'unité.
  3. Bonus : que donne nettoyer_nom("lumiere bleue") (sans accent) ? Est-ce le même éclairage pour Python ? Note la limite.
Code à copier
def nettoyer_nom(texte):
    """Renvoie le nom sans espaces autour, en minuscules, avec des espaces à la place des tirets."""
    return texte.strip().lower().replace("-", " ")


print(nettoyer_nom(" Lumière-Bleue "))
print(nettoyer_nom("LUMIÈRE BLEUE"))
print(nettoyer_nom(" Lumière-Bleue ") == nettoyer_nom("LUMIÈRE BLEUE"))

Corrigé (sortie réelle) : lumière bleue, lumière bleue, True. Sans accent, "lumiere bleue" reste différent de "lumière bleue" : nettoyer ne devine pas les fautes de frappe.

Checklist

  • Je sais utiliser indices, tranches et les méthodes strip, lower, replace.
  • Je sais qu'une méthode de chaîne renvoie une nouvelle chaîne.
  • J'affiche mes résultats avec :.2f et une unité.
[7]Journal

✍️ Journal de bord

Dans tes données de TP ou de cours, quelles incohérences de saisie (majuscules, espaces, virgules) as-tu déjà rencontrées ?

[8]Sources
  1. Python Software Foundation, Tutoriel Python — 3. Introduction informelle à Python, 3.1.2 « Chaînes de caractères », consulté le 30/10/2026.
  2. Python Software Foundation, string — Opérations usuelles sur des chaînes, « Mini-langage de spécification de format », consulté le 30/10/2026.
  3. Python Software Foundation, Nouveautés de Python 3.8 — f-strings et spécificateur =, consulté le 30/10/2026.
04
S1 · JEUDI · Pratiquer

Déboguer avec méthode

Reproduire, afficher, réduire, corriger, retester : trouver un bug même quand Python ne dit rien.

⏱ 20 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Jeudi, 10 h

Les tailles converties par Yanis sont dix fois trop grandes : 250 cm pour une plantule de 25 mm. Aucun message rouge, aucune erreur : le programme tourne et se trompe en silence. Sa première idée : réécrire toute la fonction. Awa l'arrête : « Tu ne sais même pas encore où est le problème. »

[2]Méthode

« Reproduire, afficher, réduire, corriger, retester »

Rappel : lire un message d'erreur en 3 questions (voir Boost, épisode 2). Ici, il n'y a pas de message : c'est un bug silencieux.

  1. Reproduire avec un cas dont tu connais la réponse : mm_vers_cm(25) doit donner 2.5.
  2. Afficher les valeurs intermédiaires avec un print de contrôle : print(f"CONTRÔLE {i=} {total=}").
  3. Réduire : isoler la plus petite partie du code qui montre encore le bug (une seule fonction, un seul appel).
  4. Suivre pas à pas avec un débogueur. Dans Thonny : Ctrl + F5 pour lancer en mode débogage, F6 pour un grand pas, F7 pour un petit pas, menu View → Variables pour voir les variables. VS Code a aussi un débogueur, avec des points d'arrêt.
  5. Corriger une seule chose, puis retester tous les cas connus.

Trois bugs du TP (sorties réelles) :

FonctionAppelAttenduObtenu
mm_vers_cm(taille_mm) : return taille_mm * 10mm_vers_cm(25)2.5250
numero_jour(code) : return int(code[1])numero_jour("J12")121
somme_jusqua(n) (ci-dessous)somme_jusqua(4)101
Code
def somme_jusqua(n):
    """Renvoie 1 + 2 + ... + n."""
    total = 0
    for i in range(1, n + 1):
        total = total + i
        return total


print(somme_jusqua(4))

Affiche 1. Avec un print(f"CONTRÔLE {i=} {total=}") dans la boucle, on ne voit qu'une ligne : CONTRÔLE i=1 total=1. La boucle ne fait qu'un tour : le return, décalé dans la boucle, termine la fonction dès le premier passage.

Les corrections : taille_mm / 10 ; int(code[1:]) (une tranche : tout après le J) ; return total décalé au niveau du for, après la boucle. Puis on vérifie tout :

Code
assert mm_vers_cm(25) == 2.5
assert numero_jour("J7") == 7
assert numero_jour("J12") == 12
assert somme_jusqua(4) == 10
print("Les 3 fonctions corrigées passent leurs vérifications.")

Remarque : numero_jour("J7") donnait déjà 7 avec le bug. Un seul cas de test ne suffit pas : il faut aussi "J12".

Suivre les variables · la fonction somme_jusqua boguée
Ce qui s'affiche

[3]Pourquoi ça marche

Un bug silencieux, c'est un écart entre ce que tu crois que le programme fait et ce qu'il fait vraiment. Relire le code ne montre que ce que tu crois ; afficher les valeurs, ou les suivre au débogueur, montre ce qui se passe. Réduire le problème évite de chercher dans 200 lignes ce qui tient en 5. Et corriger une seule chose à la fois permet de savoir laquelle a réglé le problème.

À retenirun cas connu, des valeurs affichées, le plus petit exemple, une correction, et on reteste tout.
[4]Entraînement

Bon réflexe ou piège ?

Je réécris toute la fonction sans savoir où est l'erreur.
tu risques de garder le bug, ou d'en ajouter un autre.
J'affiche les valeurs intermédiaires avec f"{total=}".
tu vois le nom et la valeur, sans te tromper de variable.
Je corrige trois choses d'un coup, puis je relance.
si ça marche, tu ne sais pas quelle correction était la bonne ; si ça ne marche pas, encore moins.
Je teste numero_jour avec "J7" et "J12".
un cas à un chiffre cachait le bug de l'indice.
Une fois le bug corrigé, je laisse mes print de contrôle dans le TP.
on les retire (ou on utilise le débogueur, qui ne touche pas au code).
[5]Quiz

1. somme_jusqua(4) renvoie 1. Que montre le print de contrôle dans la boucle ?

le return dans la boucle termine la fonction dès le premier tour (sortie vérifiée : CONTRÔLE i=1 total=1).

2. Pourquoi int(code[1]) est-il faux pour "J12" ?

un indice donne un seul caractère ; il faut la tranche code[1:] (sortie vérifiée : 1 au lieu de 12).

3. Dans Thonny, quelle touche lance un programme en mode débogage ?

Ctrl + F5 lance le débogage ; F6 et F7 font avancer d'un grand ou d'un petit pas.
[6]Kit

🎒 Ton kit — Épisode 4

20 min

Exercice : la chasse aux trois bugs

  1. Recopie les trois fonctions boguées (tableau et code ci-dessus).
  2. Pour chacune : écris le cas attendu, reproduis le bug, affiche les valeurs utiles, trouve la ligne fautive.
  3. Corrige une chose à la fois, puis lance les 4 vérifications.
  4. Suis somme_jusqua (version boguée, puis corrigée) au débogueur, si ton environnement en a un.

Code à copier : les vérifications ci-dessus.

Checklist

  • J'ai reproduit chaque bug avec un cas connu.
  • J'ai trouvé chaque ligne fautive en affichant les valeurs.
  • Les 4 vérifications passent après correction.
Vigilanceavant de modifier un script qui marche presque, garde une copie (ou, dès la semaine 4, un commit Git).
[7]Journal

✍️ Journal de bord

Quel est le bug le plus long que tu aies cherché ? Avec cette méthode, à quelle étape l'aurais-tu trouvé ?

[8]Sources
  1. A. Annamaa, Thonny, Python IDE for beginners, consulté le 30/10/2026.
  2. Python Software Foundation, Nouveautés de Python 3.8 — f-strings et spécificateur =, consulté le 30/10/2026.
  3. Sorties des fonctions boguées et corrigées : exécutions réelles sous Python 3.12.13 et 3.15.0 (journal de test de ce livre), le 30/10/2026.
05
S1 · VENDREDI · Pratiquer · Bilan d'arc

Écrire des fonctions : le bilan

Ton outil de synthèse, le récapitulatif de la semaine et ton badge.

⏱ 20 min · arbre de décision · carrousel · quiz final
[1]Scénario
Yanis · Vendredi, 17 h

Yanis montre ses fonctions à Awa : quatre fonctions courtes, chacune avec un nom clair, une docstring et ses vérifications. Elle lit, hoche la tête, et pose la question qui fâche : « Et si la formule de conversion change ? » Yanis sourit : « Une ligne à corriger. » Lundi, il recopiait une conversion onze fois ; aujourd'hui, il sait aussi trouver un bug sans tout réécrire.

[2]Outil

« print de contrôle ou débogueur ? »

Aide à la décision interactive
[3]Carrousel

🎨 Carrousel récapitulatif — Semaine 1

[4]Quiz final

1. Qu'affiche for i in range(4): print(i * 2) ?

i vaut 0, 1, 2, 3 ; on affiche le double (sortie vérifiée).

2. Que vaut " 12,5 mm ".strip().replace(",", ".")[:4] ?

on enlève les espaces, on remplace la virgule, puis on garde les 4 premiers caractères (sortie vérifiée).

3. Une fonction de calcul doit…

le programme principal décide ensuite quoi en faire (afficher, comparer, écrire dans un fichier).

4. assert moyenne(78.5, 6) == 78.5 / 6 ne dit rien. Qu'en conclus-tu ?

assert est silencieux quand la condition est vraie.

5. Ton résultat est faux, sans message d'erreur, dans une boucle de 50 tours. Que fais-tu d'abord ?

reproduire et afficher avant de corriger ; réduire à un petit cas évite 50 lignes d'affichage.
[5]Kit

🎒 Ton kit de fin d'arc

20 min

Les fonctions de calcul du TP

Synthèse : quatre fonctions courtes, documentées et vérifiées, réutilisables pendant tout le TP.

Code à copier
def convertir_mm(taille_cm):
    """Convertit une taille en centimètres en millimètres."""
    return taille_cm * 10


def moyenne(total, effectif):
    """Renvoie la moyenne à partir d'un total et d'un effectif non nul."""
    return total / effectif


def nettoyer_nom(texte):
    """Renvoie le nom sans espaces autour, en minuscules, avec des espaces à la place des tirets."""
    return texte.strip().lower().replace("-", " ")


def formater_resultat(nom, valeur, unite="mm"):
    """Renvoie une ligne de résultat alignée, avec 2 décimales et l'unité."""
    return f"{nettoyer_nom(nom):<15}{valeur:>8.2f} {unite}"


assert convertir_mm(2.5) == 25
assert moyenne(78.5, 6) == 78.5 / 6
assert nettoyer_nom(" Lumière-Bleue ") == "lumière bleue"
assert formater_resultat("Rouge", 9.5) == "rouge              9.50 mm"
print(formater_resultat(" Lumière-Bleue ", moyenne(78.5, 6)))
print(formater_resultat("Rouge", convertir_mm(0.95)))
print(formater_resultat("Blanche", moyenne(130, 10), "mm/jour"))

Sortie réelle :

Ce que tu vois
lumière bleue 13.08 mm rouge 9.50 mm blanche 13.00 mm/jour

Une fonction peut en appeler une autre : formater_resultat utilise nettoyer_nom.

Consigne : recopie ces fonctions dans un fichier fonctions_tp.py, ajoute une vérification de ton choix pour chacune, puis exporte ton carnet de bord (bouton dans le menu).

Checklist

  • J'ai exporté mon carnet (bouton dans le menu).
  • Mes 4 fonctions ont une docstring et au moins une vérification.
  • Je sais choisir entre print de contrôle et débogueur.
[6]Journal

✍️ Journal de bord — bilan

Qu'est-ce qui a le plus changé cette semaine dans ta façon d'écrire du code ? Qu'est-ce que tu aurais fait autrement dans tes TP précédents ?

✦ ARTISANE · ARTISAN DES FONCTIONS · SEMAINE 1 ✦

Bravo ! Tu as terminé la semaine 1. Tu sais écrire et vérifier tes propres fonctions, mettre en forme du texte et des résultats, et trouver un bug avec méthode.

ARC 2 · SEMAINE 2

Structurer tes données

Cette semaine, tes mesures quittent les variables isolées pour des listes et des dictionnaires, et ton code devient lisible par ton binôme. Vendredi, les données du TP sont rangées par éclairage et résumées en un tableau.

06
S2 · LUNDI · Comprendre

Ranger des séries de mesures dans des listes

Créer une liste, lire et modifier ses éléments, la parcourir, et la résumer avec les fonctions natives.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Lundi, 8 h

Les mesures d'une plantule sur cinq jours sont dans cinq variables : j1 = 12.0, j2 = 14.5… Pour la moyenne, Yanis écrit (j1 + j2 + j3 + j4 + j5) / 5. Puis l'enseignante annonce qu'il y aura dix jours de mesures, et trois éclairages. Trente variables. Awa lui montre une seule ligne : mesures = [12.0, 14.5, 17.0, 19.5, 23.0].

[2]Concept

La liste : plusieurs valeurs, un seul nom

Une liste range plusieurs valeurs dans l'ordre, entre crochets, séparées par des virgules. Comme une chaîne, elle est numérotée à partir de 0 ; contrairement à une chaîne, on peut la modifier.

Code
mesures = [12.0, 14.5, 17.0, 19.5, 23.0]
print(mesures[0], mesures[-1], mesures[1:3], len(mesures))
print(sum(mesures), min(mesures), max(mesures))
print(sorted(mesures, reverse=True))
mesures.append(26.5)
mesures[0] = 12.5
print(mesures)

Affiche :

Ce que tu vois
12.0 23.0 [14.5, 17.0] 5 86.0 12.0 23.0 [23.0, 19.5, 17.0, 14.5, 12.0] [12.5, 14.5, 17.0, 19.5, 23.0, 26.5]
ÉcritureCe qu'elle fait
mesures[0], mesures[-1]le premier, le dernier élément
mesures[1:3]une tranche : les éléments d'indices 1 et 2 (comme pour les chaînes, épisode 3)
len(mesures)le nombre d'éléments
mesures.append(26.5)ajoute un élément à la fin
mesures[0] = 12.5remplace un élément
sum, min, maxsomme, plus petit, plus grand
sorted(mesures)une nouvelle liste triée (reverse=True : du plus grand au plus petit)

Parcourir une liste.

Code
mesures = [12.0, 14.5, 17.0]
for mesure in mesures:
    print(mesure, "mm")
for i in range(len(mesures)):
    print("Jour", i + 1, ":", mesures[i], "mm")

La première boucle donne directement chaque valeur ; la deuxième donne les indices, utiles quand on a besoin de la position (le numéro du jour) ou de l'élément voisin. Par exemple, la croissance d'un jour à l'autre :

Code
mesures = [12.0, 14.5, 17.0, 19.5, 23.0]
croissances = []
for i in range(1, len(mesures)):
    croissances.append(mesures[i] - mesures[i - 1])
print(croissances)

Affiche [2.5, 2.5, 2.5, 3.5]. La liste vide [] grandit à chaque tour avec append.

sorted ou .sort() ? sorted(mesures) renvoie une nouvelle liste triée et ne touche pas l'originale. mesures.sort() trie la liste elle-même et renvoie None : écrire triees = mesures.sort() range None dans triees.

Une liste passée à une fonction peut être modifiée par elle.

Code
def ajouter_mesure(serie, valeur):
    """Ajoute une mesure à la fin de la série."""
    serie.append(valeur)


bleue = [12.0, 14.5]
ajouter_mesure(bleue, 17.0)
print(bleue)

Affiche [12.0, 14.5, 17.0]. La fonction reçoit la même liste, pas une copie. C'est différent d'un nombre (épisode 1) : append modifie la liste existante.

L'erreur classique : mesures[3] dans une liste de 3 éléments donne IndexError: list index out of range (« indice hors limites ») ; les indices vont de 0 à len(mesures) - 1.

Suivre les variables · une liste qui grandit, puis une boucle
Ce qui s'affiche

[3]Recherche

Ce que disent les sources

  • Tutoriel officiel de Python — list.append ajoute un élément à la fin de la liste ; list.sort ordonne les éléments de la liste elle-même. Les méthodes qui modifient la liste, comme sort, renvoient None. Pour parcourir une séquence dans l'ordre, sorted() renvoie une nouvelle liste ordonnée sans altérer la source [1].
  • Tutoriel officiel de Python — Les listes, comme les chaînes, s'indexent et se découpent en tranches ; contrairement aux chaînes, elles sont modifiables [2].
[4]Mythes
« Le premier élément est à l'indice 1. »
il est à l'indice 0 ; le dernier est à l'indice len(liste) - 1, ou -1.
« sorted(mesures) trie la liste. »
il renvoie une nouvelle liste triée ; mesures ne change pas (sortie vérifiée).
« Une liste ne contient qu'un seul type de valeur. »
elle peut mêler nombres et textes ; mais pour des mesures, garder un seul type rend les calculs possibles.
[5]Quiz

1. m = [3, 8, 5, 1]. Que valent m[1] et m[-2] ?

l'indice 1 est le deuxième élément (8) ; -2 est l'avant-dernier (5) (sortie vérifiée).

2. Que vaut sorted(m)[0] ?

sorted renvoie [1, 3, 5, 8], dont le premier élément est 1 (sortie vérifiée).

3. Après triees = mesures.sort(), que vaut triees ?

.sort() trie la liste elle-même et renvoie None (sortie vérifiée).
[6]Kit

🎒 Ton kit — Épisode 6

15 min

Exercice : prédire, puis vérifier

  1. Prédis ce qu'affiche print(m[1], m[-2], m[:2], len(m), sorted(m)[0], sum(m)) avec m = [3, 8, 5, 1], puis vérifie.
  2. Écris les mesures d'une plantule sur 5 jours dans une liste et affiche, avec une boucle, « Jour 1 : … mm », etc.
  3. Calcule la liste des croissances d'un jour à l'autre, puis la plus forte croissance avec max.

Corrigé (sortie réelle) : 8 5 [3, 8] 4 1 17.

Code à copier : le calcul des croissances ci-dessus.

Checklist

  • Je sais lire un élément, une tranche et la longueur d'une liste.
  • Je sais ajouter et modifier un élément.
  • Je fais la différence entre sorted(liste) et liste.sort().
Vigilanceune boucle for i in range(1, len(mesures)) commence à 1 parce qu'elle utilise mesures[i - 1] ; vérifie toujours le premier et le dernier tour.
[7]Journal

✍️ Journal de bord

Dans tes TP, quelles données ranges-tu aujourd'hui dans des colonnes de tableur qui pourraient devenir des listes ?

[8]Sources
  1. Python Software Foundation, Tutoriel Python — 5. Structures de données, 5.1 « Compléments sur les listes », consulté le 30/10/2026.
  2. Python Software Foundation, Tutoriel Python — 3. Introduction informelle à Python, 3.1.3 « Listes », consulté le 30/10/2026.
07
S2 · MARDI · Pratiquer

Résumer une série de mesures

Une liste en entrée, un résumé en sortie : écrire des fonctions qui résistent aux cas limites.

⏱ 20 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Mardi, 18 h

Pour le compte rendu, chaque série de mesures doit être résumée : effectif, moyenne, minimum, maximum, étendue. Yanis écrit une fonction, la teste sur une série… puis Awa lui passe la série d'une plantule morte au premier jour : une liste vide. Son programme s'arrête sur ZeroDivisionError: division by zero.

[2]Méthode

« Une liste en entrée, une valeur en sortie »

Rappels : fonctions et return (voir épisode 1), vérifications avec assert (voir épisode 2), listes (voir épisode 6).

  1. Décrire ce que renvoie la fonction, dans la docstring, y compris pour les cas limites.
  2. Traiter les cas limites d'abord : liste vide, une seule valeur.
  3. Ne pas modifier la liste reçue : on calcule, on ne trie pas en place, on n'ajoute rien.
  4. Vérifier sur un cas calculé à la main, sur une liste d'un élément et sur une liste vide.
Code
def resume(mesures):
    """Renvoie [effectif, moyenne, minimum, maximum, étendue] d'une série, ou None si elle est vide."""
    if len(mesures) == 0:
        return None
    effectif = len(mesures)
    moyenne = sum(mesures) / effectif
    minimum = min(mesures)
    maximum = max(mesures)
    return [effectif, moyenne, minimum, maximum, maximum - minimum]


print(resume([12, 14, 16]))
print(resume([5.0]))
print(resume([]))
assert resume([12, 14, 16]) == [3, 14.0, 12, 16, 4]
assert resume([]) is None
print("Vérifications : OK")

Sortie réelle :

Ce que tu vois
[3, 14.0, 12, 16, 4] [1, 5.0, 5.0, 5.0, 0.0] None Vérifications : OK

Sans le test du début, une liste vide provoque ZeroDivisionError: division by zero (diviser par len([]), qui vaut 0), et max([]) s'arrête sur ValueError: max() iterable argument is empty. La fonction choisit de renvoyer None : à celui qui l'appelle de décider quoi faire d'une série vide. On teste None avec is None.

Cette fonction renvoie cinq valeurs dans une liste ; demain, tu verras une façon plus adaptée de renvoyer plusieurs valeurs : le tuple.

[3]Pourquoi ça marche

Les vraies données ont des trous : une plantule morte, un jour sans mesure, un fichier vide. Une fonction qui marche « sur l'exemple » mais s'arrête sur une série vide fera planter tout le TP le jour du rendu. En traitant les cas limites en premier et en les vérifiant, tu sais exactement ce que fait ta fonction dans tous les cas, et ton binôme aussi : c'est écrit dans la docstring.

À retenircas limites d'abord ; on ne modifie pas la liste reçue ; on vérifie le cas normal, un élément, une liste vide.
[4]Entraînement

Bon réflexe ou piège ?

Je teste ma fonction seulement sur l'exemple du sujet.
une série vide ou d'un seul élément la fera peut-être planter.
Je trie la liste reçue avec .sort() pour trouver le minimum.
tu modifies la liste de celui qui appelle la fonction ; min suffit.
J'écris dans la docstring ce que renvoie la fonction pour une liste vide.
le comportement aux limites fait partie du contrat de la fonction.
Dans la boucle, je recalcule sum(mesures) à chaque tour.
c'est le même total à chaque fois ; on le calcule une seule fois.
Je vérifie mon résultat avec un cas calculé à la main.
sans résultat attendu, impossible de savoir si le résultat obtenu est juste.
[5]Quiz

1. Que renvoie resume([5.0]) ?

une seule mesure : effectif 1, moyenne, minimum et maximum égaux, étendue nulle (sortie vérifiée).

2. Pourquoi sum([]) / len([]) s'arrête-t-il ?

len([]) vaut 0 : ZeroDivisionError: division by zero (sortie vérifiée).

3. Comment vérifier qu'une fonction renvoie None ?

None se teste avec is None.
[6]Kit

🎒 Ton kit — Épisode 7

20 min

Exercice : ta fonction resume

  1. Écris resume(mesures) et ses vérifications (cas normal, un élément, liste vide).
  2. Résume les séries [12.0, 14.5, 17.0, 19.5, 23.0] et [11.0, 12.5, 13.0, 15.5, 16.0].
  3. Bonus : écris croissance_moyenne(mesures) (moyenne des écarts d'un jour à l'autre). Que renvoie-t-elle pour une série d'une seule mesure ? Décide, écris-le dans la docstring, vérifie-le.

Code à copier : la fonction resume ci-dessus.

Checklist

  • Ma fonction traite la liste vide sans planter.
  • Elle ne modifie pas la liste reçue.
  • Elle passe ses vérifications.
[7]Journal

✍️ Journal de bord

Quel cas limite tes données de TP pourraient-elles contenir (valeur manquante, série vide, valeur aberrante) ? Comment ta fonction devrait-elle réagir ?

[8]Sources
  1. Python Software Foundation, Fonctions natives — sum, min, max, len, consulté le 30/10/2026.
  2. Sorties de resume et des erreurs sur une liste vide : exécutions réelles sous Python 3.12.13 et 3.15.0 (journal de test de ce livre), le 30/10/2026.
08
S2 · MERCREDI · Comprendre

Dictionnaires, tuples et ensembles

Retrouver des données par un nom, grouper des valeurs qui vont ensemble, garder les valeurs distinctes.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Mercredi, 14 h

Trois éclairages, trois listes : mesures_bleue, mesures_rouge, mesures_blanche. Pour ajouter un quatrième éclairage, il faudrait une quatrième variable et modifier chaque boucle. Et Yanis voudrait savoir combien de jours différents ont été mesurés, certains ayant été notés deux fois. Awa : « Tu as besoin d'un dictionnaire. Et peut-être d'un ensemble. »

[2]Concept

Trois nouvelles structures

Le dictionnaire : des valeurs rangées sous des clés.

Code
mesures = {
    "bleue": [12.0, 14.5, 17.0, 19.5, 23.0],
    "rouge": [11.0, 12.5, 13.0, 15.5, 16.0],
}
mesures["blanche"] = [12.5, 15.0, 18.5, 21.0, 25.0]
print(list(mesures))
print(mesures["rouge"][-1])
print("verte" in mesures, mesures.get("verte"))
for eclairage, serie in mesures.items():
    print(eclairage, len(serie), max(serie))

Affiche :

Ce que tu vois
['bleue', 'rouge', 'blanche'] 16.0 False None bleue 5 23.0 rouge 5 16.0 blanche 5 25.0
  • Un dictionnaire associe des clés (ici les noms d'éclairage) à des valeurs (ici des listes). Les clés sont uniques.
  • mesures["rouge"] lit une valeur ; mesures["blanche"] = … ajoute ou remplace.
  • "verte" in mesures teste si une clé existe ; mesures.get("verte") renvoie None au lieu de s'arrêter. Lire une clé absente directement, mesures["verte"], provoque KeyError: 'verte'.
  • .items() donne les paires (clé, valeur) dans une boucle ; les clés gardent l'ordre d'insertion.
  • Un dictionnaire de listes range toutes les séries du TP sous un seul nom : ajouter un éclairage, c'est ajouter une clé.

Le tuple : des valeurs groupées qui ne changent pas.

Code
def min_max(serie):
    """Renvoie le minimum et le maximum d'une série non vide."""
    return min(serie), max(serie)


bas, haut = min_max([12.0, 14.5, 17.0])
print(bas, haut)
resultat = min_max([11.0, 16.0])
print(resultat, type(resultat))
resultat[0] = 0

Affiche 12.0 17.0, puis (11.0, 16.0) <class 'tuple'>, puis s'arrête : TypeError: 'tuple' object does not support item assignment. Un tuple s'écrit entre parenthèses (ou simplement avec des virgules) ; on ne peut pas le modifier. C'est la façon habituelle de renvoyer plusieurs valeurs : return a, b renvoie un tuple, et bas, haut = … le déballe dans deux variables.

L'ensemble : des valeurs distinctes.

Code
jours = ["J1", "J2", "J2", "J3", "J1"]
distincts = set(jours)
print(len(jours), len(distincts))
print("J4" in distincts)
print(sorted(distincts))
lot_a = {"bleue", "rouge"}
lot_b = {"rouge", "blanche"}
print(sorted(lot_a & lot_b), sorted(lot_a | lot_b))
print(type({}), type(set()))

Affiche :

Ce que tu vois
5 3 False ['J1', 'J2', 'J3'] ['rouge'] ['blanche', 'bleue', 'rouge'] <class 'dict'> <class 'set'>

Un ensemble (set) ne garde chaque valeur qu'une fois, et n'a pas d'ordre (on trie avec sorted pour l'afficher). & donne les éléments communs, | la réunion. Attention : {} crée un dictionnaire vide ; un ensemble vide s'écrit set().

Ton besoinLa structure
une série ordonnée, qui peut grandirliste [...]
retrouver une valeur par un nomdictionnaire {clé: valeur}
quelques valeurs qui vont ensemble et ne changent pas, renvoyer plusieurs valeurstuple (a, b)
des valeurs distinctes, tester l'appartenanceensemble set(...)
[3]Recherche

Ce que disent les sources

  • Tutoriel officiel de Python — Un dictionnaire est un ensemble de paires clé-valeur dont les clés doivent être uniques ; list(d) renvoie les clés dans l'ordre d'insertion (sorted(d) pour les avoir triées) [1].
  • Python 3.7 (2018) — L'ordre d'insertion des dictionnaires est garanti par le langage depuis la version 3.7 [2].
  • Tutoriel officiel de Python — Les n-uplets (tuples) sont immuables ; on accède à leurs éléments par indice ou par déballage, qui demande autant de variables que d'éléments [1].
  • Tutoriel officiel de Python — Un ensemble est une collection non ordonnée sans doublons ; il sert notamment à tester l'appartenance et à éliminer les doublons. {} crée un dictionnaire vide ; on utilise set() pour un ensemble vide [1].
[4]Mythes
« Un dictionnaire est trié par clé. »
il garde l'ordre dans lequel les clés ont été ajoutées (« blanche » arrive en dernier parce qu'elle a été ajoutée en dernier).
« Un tuple, c'est une liste en moins bien. »
il ne change pas, c'est voulu : un résultat renvoyé ne doit pas être modifié par erreur.
« Un ensemble garde l'ordre. »
il n'a pas d'ordre ; pour un affichage stable, on le trie.
[5]Quiz

1. Que fait mesures.get("verte") si la clé "verte" n'existe pas ?

get renvoie None (ou une valeur par défaut) ; c'est mesures["verte"] qui provoque une KeyError (sorties vérifiées).

2. bas, haut = min_max([12.0, 14.5, 17.0]). Que vaut haut ?

la fonction renvoie un tuple de deux valeurs, déballé dans bas et haut (sortie vérifiée).

3. Que vaut len(set(["J1", "J2", "J2", "J3", "J1"])) ?

l'ensemble ne garde que les valeurs distinctes : J1, J2, J3 (sortie vérifiée).
[6]Kit

🎒 Ton kit — Épisode 8

20 min

Exercice : ranger les mesures du TP

  1. Range les trois séries dans un dictionnaire mesures (clé = éclairage), puis ajoute un quatrième éclairage, « verte », avec des mesures inventées.
  2. Avec une boucle sur .items(), affiche pour chaque éclairage le nombre de mesures et la valeur maximale.
  3. Écris min_max(serie) qui renvoie un tuple, et utilise le déballage.
  4. Une liste de codes de jours contient des doublons : compte les jours distincts avec un ensemble.

Code à copier : le dictionnaire de listes ci-dessus.

Checklist

  • Je sais lire, ajouter et parcourir les paires d'un dictionnaire.
  • Je sais renvoyer et déballer un tuple.
  • Je sais éliminer les doublons avec un ensemble.
Vigilancepour une clé qui peut manquer, utilise in ou get plutôt que de laisser le programme s'arrêter sur une KeyError.
[7]Journal

✍️ Journal de bord

Dans tes données d'études (TP, notes, emploi du temps), qu'est-ce qui se range naturellement dans un dictionnaire ? Quelle serait la clé ?

[8]Sources
  1. Python Software Foundation, Tutoriel Python — 5. Structures de données, 5.3 « n-uplets et séquences », 5.4 « Ensembles », 5.5 « Dictionnaires », consulté le 30/10/2026.
  2. Python Software Foundation, modification de la documentation des types natifs : « Dict order is guaranteed to be insertion order » (version 3.7), annonce python-checkins de juin 2018, consulté le 30/10/2026. (mail.python.org/pipermail/python-checkins/2018-June/155422.html)
09
S2 · JEUDI · Pratiquer

Un code que ton binôme peut lire

Relire ton code comme s'il était celui d'un autre : noms, docstrings, commentaires, constantes et règles de la PEP 8.

⏱ 20 min de pratique · 5 min de quiz
[1]Scénario
Awa · Jeudi, 10 h

Yanis est malade. Awa doit finir la partie « moyennes » du TP à partir de son script. Elle ouvre le fichier : f(l), l2, tmp, t=t+x sur la même ligne que le for. Le programme marche, mais elle met vingt minutes à comprendre ce qu'il fait. Le soir, elle lui envoie un message : « Ton code marche. Mais il faut que je puisse le lire. »

[2]Méthode

« Relire comme si c'était le code d'un autre »

Rappels : docstrings et nommage des fonctions (voir épisode 1).

  1. Des noms qui disent ce qu'ils contiennent : tailles_bleue plutôt que l2, moyenne_bleue plutôt que tmp. Fonctions nommées par une action.
  2. Une docstring par fonction : ce qu'elle fait, ce qu'elle renvoie, ses cas limites.
  3. Des commentaires qui expliquent pourquoi, pas ce que dit déjà le code (# on exclut le jour 0 : graines non germées, et non # on ajoute 1).
  4. Des constantes en majuscules, en haut du fichier, pour les valeurs fixées : NB_DECIMALES = 1.
  5. Les règles de la PEP 8, le guide de style officiel : 4 espaces par niveau ; lignes de 79 caractères au plus ; deux lignes vides avant et après chaque fonction ; noms de fonctions et de variables en minuscules avec des _ ; une espace autour de = et des opérateurs.
  6. Vérifier que le résultat n'a pas changé : même sortie avant et après la réécriture.

Avant :

Code
def f(l):
    t=0
    for x in l:t=t+x
    return t/len(l)
l2=[12.0,14.5,17.0,19.5,23.0]
tmp=f(l2)
print(round(tmp,1))

Après :

Code
NB_DECIMALES = 1


def moyenne(mesures):
    """Renvoie la moyenne d'une série de mesures non vide."""
    total = 0
    for mesure in mesures:
        total = total + mesure
    return total / len(mesures)


tailles_bleue = [12.0, 14.5, 17.0, 19.5, 23.0]
moyenne_bleue = moyenne(tailles_bleue)
print(round(moyenne_bleue, NB_DECIMALES))

Les deux versions affichent 17.2 (sorties vérifiées). Le comportement est identique ; seule la lecture a changé.

Auto-diagnostic · mon code est-il lisible ?
  • Mes noms disent ce qu'ils contiennent.
  • Mes fonctions sont nommées par une action et ont une docstring.
  • Mes commentaires expliquent pourquoi.
  • Mes valeurs fixées sont des constantes en majuscules.
  • 4 espaces, lignes courtes, deux lignes vides entre fonctions.
  • La sortie est la même qu'avant ma relecture.
[3]Pourquoi ça marche

Un code est lu bien plus souvent qu'il n'est écrit : par toi dans trois semaines, par ton binôme, par ton correcteur. Chaque nom clair épargne une question ; chaque docstring épargne une lecture ligne à ligne. Et des règles communes, comme celles de la PEP 8, font que tous les codes Python se ressemblent : on se concentre sur ce qu'ils font, pas sur leur présentation.

À reteniron écrit pour être relu ; on vérifie que la relecture n'a rien changé au résultat.
[4]Entraînement

Bon réflexe ou piège ?

Je commente chaque ligne : # on ajoute 1 à i.
le commentaire répète le code ; explique plutôt pourquoi.
J'abrège tous mes noms pour aller plus vite : m, s, r.
tu gagnes trois secondes à l'écriture, ton binôme perd dix minutes à la lecture.
Je range les valeurs fixées en constantes en haut du fichier.
une valeur à changer, un seul endroit.
Je vérifie que la sortie est la même avant et après ma réécriture.
rendre le code lisible ne doit rien casser.
Je mets le corps d'une boucle sur la même ligne que le for.
c'est permis, mais difficile à lire et à déboguer ; la PEP 8 le déconseille.
[5]Quiz

1. Quel nom de variable est le plus lisible pour une liste de tailles sous lumière bleue ?

il dit ce qu'il contient, en minuscules avec _, comme le recommande la PEP 8.

2. Selon la PEP 8, combien de lignes vides autour d'une fonction définie au niveau du fichier ?

deux lignes vides avant et après chaque définition de fonction de premier niveau.

3. Quel commentaire est utile ?

il explique un choix que le code seul ne dit pas.
[6]Kit

🎒 Ton kit — Épisode 9

20 min

Exercice : réécrire sans rien casser

  1. Lance la version « avant » et note sa sortie.
  2. Réécris-la en appliquant la méthode, sans regarder la version « après ».
  3. Lance ta version : la sortie doit être identique.
  4. Coche l'auto-diagnostic, puis applique la même relecture à ta fonction resume de mardi.

Code à copier : la version « après » ci-dessus.

Checklist

  • Mes noms, docstrings et commentaires passent la relecture.
  • Mon code suit les règles principales de la PEP 8.
  • La sortie est identique avant et après.
[7]Journal

✍️ Journal de bord

Relis un de tes anciens scripts de TP. Qu'est-ce qui t'empêche de le comprendre aujourd'hui ?

[8]Sources
  1. G. van Rossum, B. Warsaw, A. Coghlan, PEP 8 – Style Guide for Python Code, consulté le 30/10/2026.
  2. D. Goodger, G. van Rossum, PEP 257 – Docstring Conventions, consulté le 30/10/2026.
10
S2 · VENDREDI · Pratiquer · Bilan d'arc

Structurer tes données : le bilan

Ton outil de synthèse, le récapitulatif de la semaine et ton badge.

⏱ 20 min · arbre de décision · carrousel · quiz final
[1]Scénario
Yanis · Vendredi, 17 h

Yanis est de retour. Awa a repris sa partie, et lui la relit : il comprend tout du premier coup, y compris ce qu'elle a ajouté. Ensemble, ils rangent les mesures du TP dans un dictionnaire, résument chaque éclairage et affichent un tableau aligné. Lundi, il avait trente variables en tête ; aujourd'hui, un seul dictionnaire.

[2]Outil

« Liste, dictionnaire, tuple ou ensemble ? »

Aide à la décision interactive
[3]Carrousel

🎨 Carrousel récapitulatif — Semaine 2

[4]Quiz final

1. d = {"a": [1, 2], "b": [3]}, puis d["a"].append(5). Que vaut sum(d["a"]) ?

la liste de la clé "a" devient [1, 2, 5], de somme 8 (sortie vérifiée).

2. Que vaut len({3, 1, 3, 2, 1}) ?

l'ensemble ne garde que 1, 2 et 3 (sortie vérifiée).

3. Ta fonction doit renvoyer le minimum et le maximum. Tu écris…

un seul return avec deux valeurs renvoie un tuple ; un deuxième return ne serait jamais atteint.

4. Pourquoi resume([]) renvoie-t-elle None plutôt que de planter ?

le cas limite est traité avant toute division.

5. Quel nom respecte la PEP 8 pour une constante ?

les constantes s'écrivent en majuscules, avec des _ entre les mots.
[5]Kit

🎒 Ton kit de fin d'arc

20 min

Les mesures du TP, résumées par éclairage

Synthèse : un dictionnaire de listes, une fonction de résumé vérifiée, un tableau aligné.

Code à copier
MESURES = {
    "bleue": [12.0, 14.5, 17.0, 19.5, 23.0],
    "rouge": [11.0, 12.5, 13.0, 15.5, 16.0],
    "blanche": [12.5, 15.0, 18.5, 21.0, 25.0],
}


def resume(mesures):
    """Renvoie (effectif, moyenne, minimum, maximum, étendue) d'une série, ou None si elle est vide."""
    if len(mesures) == 0:
        return None
    effectif = len(mesures)
    minimum = min(mesures)
    maximum = max(mesures)
    return effectif, sum(mesures) / effectif, minimum, maximum, maximum - minimum


assert resume([12, 14, 16]) == (3, 14.0, 12, 16, 4)
assert resume([]) is None

print(f"{'Éclairage':<10}{'n':>3}{'moyenne':>9}{'min':>7}{'max':>7}{'étendue':>9}")
for eclairage, serie in MESURES.items():
    effectif, moyenne, minimum, maximum, etendue = resume(serie)
    print(f"{eclairage:<10}{effectif:>3}{moyenne:>9.2f}{minimum:>7.1f}{maximum:>7.1f}{etendue:>9.1f}")

Sortie réelle :

Ce que tu vois
Éclairage n moyenne min max étendue bleue 5 17.20 12.0 23.0 11.0 rouge 5 13.60 11.0 16.0 5.0 blanche 5 18.40 12.5 25.0 12.5

resume renvoie maintenant un tuple, déballé en cinq variables. Les mesures sont encore écrites dans le code : la semaine prochaine, elles viendront d'un vrai fichier.

Consigne : ajoute l'éclairage « verte » au dictionnaire et vérifie que le tableau s'allonge sans rien changer d'autre. Puis exporte ton carnet de bord (bouton dans le menu).

Checklist

  • J'ai exporté mon carnet (bouton dans le menu).
  • Mes mesures sont rangées dans un dictionnaire de listes.
  • Mon tableau de résumé s'affiche aligné, avec 2 décimales pour la moyenne.
[6]Journal

✍️ Journal de bord — bilan

Quelle structure (liste, dictionnaire, tuple, ensemble) as-tu eu le plus de mal à choisir cette semaine ? Pourquoi ?

✦ ARCHITECTE DES DONNÉES · SEMAINE 2 ✦

Bravo ! Tu as terminé la semaine 2. Tu sais ranger des données dans des listes, des dictionnaires, des tuples et des ensembles, écrire des fonctions qui les résument, et un code que d'autres peuvent lire.

ARC 3 · SEMAINE 3

Fichiers et bibliothèques

Cette semaine, tu t'appuies sur les outils fournis avec Python, tu lis tes mesures dans un vrai fichier et tu installes proprement les bibliothèques d'analyse. Vendredi, ton TP lit son CSV et écrit son résumé tout seul.

11
S3 · LUNDI · Comprendre

La bibliothèque standard

Importer les modules fournis avec Python (math, statistics, random, datetime) au lieu de tout réécrire.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Lundi, 8 h

Le sujet du TP demande l'écart type de chaque série. Yanis a écrit sa propre fonction, fier de lui : 3,83 pour la lumière bleue. Le corrigé de l'exemple indique 4,28. Il relit sa formule dix fois sans trouver d'erreur de frappe. Awa : « Tu sais que c'est déjà dans Python ? Et que les deux résultats sont peut-être justes ? »

[2]Concept

Les modules fournis avec Python

Python est livré avec une bibliothèque standard : des centaines de modules prêts à l'emploi. On les importe en haut du fichier.

Code
import math
import statistics
from datetime import date

mesures = [12.0, 14.5, 17.0, 19.5, 23.0]
print(statistics.mean(mesures), statistics.median(mesures))
print(round(statistics.stdev(mesures), 2), round(statistics.pstdev(mesures), 2))
print(math.sqrt(16), round(math.pi, 4))
print(date(2026, 10, 30).strftime("%d/%m/%Y"))

Affiche :

Ce que tu vois
17.2 17.0 4.28 3.83 4.0 3.1416 30/10/2026

Trois façons d'importer.

ÉcritureUtilisation
import statisticsstatistics.mean(...) : on voit d'où vient la fonction
from datetime import datedate(...) directement
import statistics as stst.median(...) : un alias plus court

Quatre modules utiles en TP.

  • math : sqrt (racine carrée), pi, log, exp…
  • statistics : mean (moyenne), median (médiane), stdev (écart type d'un échantillon), pstdev (écart type d'une population entière).
  • random : random(), randint(a, b), choice(liste) ; random.seed(42) fixe le point de départ du tirage, pour reproduire exactement les mêmes tirages (utile pour un TP qu'on doit pouvoir relancer).
  • datetime : date.today() (la date du jour), strftime("%d/%m/%Y") pour l'écrire à la française.

Le mystère de Yanis. Sa fonction divisait la somme des carrés des écarts par l'effectif n : c'est l'écart type de population (pstdev, 3,83). Le sujet demande celui d'un échantillon (stdev, 4,28), qui divise par n − 1. Les deux formules existent ; le module les nomme clairement, et sa documentation dit laquelle est laquelle.

Rappel : ne nomme jamais un de tes fichiers comme un module (statistics.py, random.py) : import chargerait ton fichier à la place du vrai module.

Remets les lignes dans l'ordre · clique les lignes une par une
Ton programme
Lignes à placer
[3]Recherche

Ce que disent les sources

  • Documentation officielle de statistics — mean renvoie la moyenne arithmétique ; median la valeur centrale (moyenne des deux valeurs centrales si l'effectif est pair) ; stdev l'écart type d'échantillon (racine carrée de la variance d'échantillon) ; pstdev l'écart type de population [1].
  • Documentation officielle de random — Le module produit des nombres pseudo-aléatoires ; random.seed initialise le générateur, ce qui permet de reproduire une suite de tirages [2].
  • Tests de ce livre — Avec random.seed(42), le même tirage (blanche 1) est obtenu deux fois de suite, sous Python 3.12.13 comme sous 3.15.0 (journal de test).
[4]Mythes
« Pour faire des statistiques en Python, il faut installer une bibliothèque. »
moyenne, médiane et écart type sont dans statistics, fourni avec Python.
« Mes calculs écrits à la main sont plus fiables. »
ceux de la bibliothèque standard sont testés par des milliers d'utilisateurs ; et le nom de la fonction dit quelle formule elle applique.
« Le hasard de l'ordinateur est vraiment aléatoire. »
il est pseudo-aléatoire : calculé à partir d'une graine ; avec la même graine, on obtient les mêmes tirages.
[5]Quiz

1. Que renvoie statistics.median([4, 1, 3, 2]) ?

effectif pair : moyenne des deux valeurs centrales, 2 et 3 (sortie vérifiée).

2. Le sujet demande l'écart type d'un échantillon de plantules. Quelle fonction ?

stdev calcule l'écart type d'échantillon ; pstdev celui d'une population entière.

3. Après import statistics as st, comment calculer une moyenne ?

l'alias st remplace le nom du module.
[6]Kit

🎒 Ton kit — Épisode 11

15 min

Exercice : remplacer tes calculs par la bibliothèque standard

  1. Calcule la moyenne, la médiane et les deux écarts types de chaque série du TP avec statistics.
  2. Compare avec ta fonction resume de la semaine 2 : les moyennes doivent être identiques.
  3. Affiche la date du jour au format JJ/MM/AAAA au-dessus de ton tableau de résultats.
  4. Tire au hasard l'ordre de passage de trois éclairages, avec une graine, et vérifie que le tirage se reproduit.

Code à copier : le programme du concept.

Checklist

  • Je sais importer un module de trois façons.
  • Je sais quand utiliser stdev et pstdev.
  • Je sais reproduire un tirage avec random.seed.
Vigilancen'appelle aucun de tes fichiers statistics.py, random.py ou math.py.
[7]Journal

✍️ Journal de bord

Quel calcul de tes cours (statistiques, conversions, dates) as-tu déjà écrit à la main alors qu'il existait peut-être dans la bibliothèque standard ?

[8]Sources
  1. Python Software Foundation, statistics — Fonctions mathématiques pour les statistiques, consulté le 30/10/2026.
  2. Python Software Foundation, random — Génère des nombres pseudo-aléatoires, consulté le 30/10/2026.
12
S3 · MARDI · Pratiquer

Lire la documentation d'un module

Chercher, lire la fiche, essayer l'exemple, adapter : trouver seul une fonction et son mode d'emploi.

⏱ 20 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Mardi, 18 h

L'énoncé demande « la médiane et l'écart type de l'échantillon ». Sur un forum, une réponse de 2015 propose une fonction qui n'existe plus ; une autre utilise pstdev. Yanis ne sait plus qui croire. Awa : « Il y a une source qui a toujours raison pour ta version de Python : la documentation officielle. »

[2]Méthode

« Chercher, lire la fiche, essayer l'exemple, adapter »

Rappel : importer un module (voir épisode 11).

  1. Chercher dans la documentation officielle, en français : docs.python.org/fr, rubrique « Référence de la bibliothèque », puis le module. Choisis ta version de Python dans le menu en haut de la page.
  2. Lire la fiche d'une fonction : son nom et ses paramètres (stdev(data, xbar=None)), ce qu'elle renvoie, ses cas limites (« au moins deux valeurs », exceptions).
  3. Essayer l'exemple tel quel, dans la console, avant de l'adapter.
  4. Adapter à tes données, puis vérifier sur un cas connu.
  5. Dans la console, help(statistics.stdev) affiche la documentation de la fonction ; statistics.stdev.__doc__ aussi.

Exemple réel : print(statistics.stdev.__doc__.splitlines()[0]) affiche Return the square root of the sample variance. (« Renvoie la racine carrée de la variance d'échantillon. ») : la confirmation que stdev est bien l'écart type d'échantillon.

Quelques formats de date (strftime) : %d jour, %m mois, %Y année sur 4 chiffres, %H:%M heures et minutes. date(2026, 10, 30).strftime("%d/%m/%Y") donne 30/10/2026.

[3]Pourquoi ça marche

La documentation officielle correspond exactement à ta version de Python : elle ne peut pas proposer une fonction qui n'existe pas, ni une formule ancienne. Les réponses de forums sont utiles pour des idées, mais elles datent, se contredisent, et répondent souvent à une autre question. Essayer l'exemple tel quel, avant de l'adapter, sépare deux problèmes : « la fonction marche-t-elle ? » et « l'ai-je bien utilisée ? ».

À retenirla documentation de ta version d'abord ; l'exemple tel quel, puis adapté ; un cas connu pour vérifier.
[4]Entraînement

Bon réflexe ou piège ?

Je copie la première réponse d'un forum sans regarder sa date.
elle peut concerner une ancienne version, ou un autre problème.
Je choisis ma version de Python dans le menu de la documentation.
une fonction peut apparaître ou changer d'une version à l'autre.
Je lis la fiche jusqu'aux cas limites (« au moins deux valeurs »).
c'est là que se cachent les erreurs de demain.
J'adapte l'exemple à mes données avant de l'avoir essayé tel quel.
si ça ne marche pas, tu ne sauras pas si c'est la fonction ou ton adaptation.
J'utilise help() dans la console pour vérifier ce que fait une fonction.
la documentation est aussi dans Python.
[5]Quiz

1. Où trouver la fiche officielle de statistics.stdev ?

la référence de la bibliothèque décrit chaque module et chaque fonction.

2. Que donne date(2026, 10, 30).strftime("%d/%m/%Y") ?

%d jour, %m mois, %Y année (sortie vérifiée).

3. Pourquoi essayer l'exemple de la documentation tel quel d'abord ?

on sépare « la fonction marche » et « je l'utilise bien ».
[6]Kit

🎒 Ton kit — Épisode 12

20 min

Exercice : trois réponses dans la documentation

  1. Dans la fiche de statistics, trouve ce que fait median quand l'effectif est pair. Vérifie avec [12.0, 14.5, 17.0, 19.5].
  2. Trouve ce que provoque stdev avec une seule valeur. Note-le (tu ne le corriges pas : la gestion des erreurs arrive dans le Master).
  3. Dans la fiche de datetime, trouve le format qui écrit aussi l'heure (%H:%M) et affiche un horodatage pour ton résumé de TP.

Corrigé : median([12.0, 14.5, 17.0, 19.5]) donne 15.75 (moyenne de 14,5 et 17,0, sortie vérifiée).

Code à copier : aucun ; tu écris tes propres essais.

Checklist

  • J'ai trouvé les 3 réponses dans la documentation officielle.
  • J'ai essayé chaque exemple tel quel avant de l'adapter.
  • Je sais utiliser help() dans la console.
[7]Journal

✍️ Journal de bord

Quelle réponse de forum t'a déjà induit en erreur ? Comment l'aurais-tu vérifiée ?

[8]Sources
  1. Python Software Foundation, Documentation Python 3.15 — référence de la bibliothèque, consulté le 30/10/2026.
  2. Python Software Foundation, datetime — Types de base pour la date et l'heure, codes de format de strftime, consulté le 30/10/2026.
13
S3 · MERCREDI · Comprendre

Lire et écrire des fichiers CSV et JSON

Construire un chemin, ouvrir un fichier proprement, lire un CSV de tableur, écrire et relire un JSON.

⏱ 25 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Mercredi, 14 h

Les mesures arrivent enfin dans un vrai fichier, croissance.csv, exporté du tableur de la salle de TP. Yanis l'ouvre dans un éditeur de texte : des points-virgules partout, et des virgules à la place des points dans les nombres. Il essaie de le lire avec le module csv… et obtient ['J1;bleue;12', '0']. Awa : « Ton tableur est français. Il faut le dire à Python. »

[2]Concept

Les fichiers

Le fichier du TP (15 lignes de mesures, données inventées) commence ainsi :

Début du fichier croissance.csv
jour;eclairage;taille_mm J1;bleue;12,0 J2;bleue;14,5 J3;bleue;17,0

Un CSV (comma-separated values) est un tableau écrit en texte, une ligne par enregistrement. Les tableurs réglés en français séparent les colonnes par des points-virgules, parce que la virgule sert de séparateur décimal.

1. Le chemin : pathlib.

Code
from pathlib import Path

DOSSIER = Path(__file__).parent
chemin = DOSSIER / "croissance.csv"
print(chemin.name, chemin.exists())

Affiche croissance.csv True. Path(__file__).parent est le dossier du script ; l'opérateur / assemble les morceaux d'un chemin, sous Windows comme sous macOS ou Linux. (__file__ n'existe pas dans une console ou un notebook : on écrit alors Path("croissance.csv"), relatif au dossier de travail.)

2. Lire un CSV avec csv.DictReader.

Code
import csv

mesures = {}
with open(chemin, encoding="utf-8") as fichier:
    lecteur = csv.DictReader(fichier, delimiter=";")
    for ligne in lecteur:
        eclairage = ligne["eclairage"]
        taille = float(ligne["taille_mm"].replace(",", "."))
        if eclairage not in mesures:
            mesures[eclairage] = []
        mesures[eclairage].append(taille)
print(mesures)

Affiche le dictionnaire de listes de la semaine 2 : {'bleue': [12.0, 14.5, 17.0, 19.5, 23.0], 'rouge': [11.0, 12.5, 13.0, 15.5, 16.0], 'blanche': [12.5, 15.0, 18.5, 21.0, 25.0]}.

  • with open(…) as fichier: ouvre le fichier et le referme automatiquement à la fin du bloc, même en cas d'erreur.
  • encoding="utf-8" précise l'encodage (la façon dont les caractères, accents compris, sont écrits en octets). Depuis Python 3.15, UTF-8 est l'encodage par défaut ; l'écrire reste utile, car beaucoup d'ordinateurs ont encore une version plus ancienne.
  • DictReader lit la première ligne comme en-tête : chaque ligne devient un dictionnaire (ligne["taille_mm"]). Tout est lu comme texte : on convertit, après avoir remplacé la virgule décimale.
  • csv.reader (sans Dict) donne des listes : ['jour', 'eclairage', 'taille_mm'], puis ['J1', 'bleue', '12,0'].
  • Avec le mauvais séparateur (delimiter=","), on obtient ['J1;bleue;12', '0'] : la ligne est coupée à la virgule décimale.

3. Écrire et relire un JSON. Le JSON est un format texte pour des données structurées (dictionnaires, listes, nombres, textes), lisible par presque tous les langages.

Code
import json

resume = {"bleue": {"n": 5, "moyenne": 17.2}, "rouge": {"n": 5, "moyenne": 13.6}}
with open(DOSSIER / "resume_essai.json", "w", encoding="utf-8") as fichier:
    json.dump(resume, fichier, ensure_ascii=False, indent=2)
with open(DOSSIER / "resume_essai.json", encoding="utf-8") as fichier:
    relu = json.load(fichier)
print(relu["rouge"]["moyenne"], relu == resume)

Affiche 13.6 True. Le mode "w" (write) crée le fichier, ou l'écrase s'il existe ; indent=2 le rend lisible ; ensure_ascii=False garde les accents tels quels.

4. Si le fichier n'existe pas : open(Path("croissanse.csv")) (une faute de frappe) s'arrête sur FileNotFoundError: [Errno 2] No such file or directory: 'croissanse.csv'. chemin.exists() permet de vérifier avant.

Lecteur de CSV simulé · les 4 premières lignes de croissance.csv
Séparateur :
Fonction :
Code
Ce que Python obtient, ligne par ligne

Sorties produites par le module csv de Python au moment de la fabrication du livre.

[3]Recherche

Ce que disent les sources

  • Documentation officielle de csv — csv.reader renvoie chaque ligne sous forme de liste de chaînes ; csv.DictReader utilise la première ligne comme noms de champs et renvoie chaque ligne sous forme de dictionnaire ; le paramètre delimiter fixe le séparateur [1].
  • Documentation officielle de json — json.dump écrit un objet Python dans un fichier au format JSON, json.load le relit ; ensure_ascii=False conserve les caractères non ASCII [2].
  • Documentation officielle de pathlib — Path représente un chemin ; l'opérateur / joint ses parties ; exists() indique si le fichier existe [3].
  • Python 3.15 — Le mode UTF-8 devient le mode par défaut (PEP 686) : une ouverture de fichier texte sans encodage précisé utilise UTF-8, quel que soit le système ; avant 3.15, l'encodage dépendait des réglages régionaux, surtout sous Windows [4].
[4]Mythes
« Un CSV, c'est toujours des virgules. »
avec un tableur français, c'est souvent des points-virgules, et la virgule est le séparateur décimal.
« open sans with, c'est pareil. »
sans with, il faut penser à refermer le fichier soi-même, y compris quand une erreur arrête le programme.
« Le JSON, c'est du Python. »
c'est un format texte indépendant du langage ; il ressemble aux dictionnaires Python, mais n'a ni tuples ni ensembles.
[5]Quiz

1. Le fichier contient J1;bleue;12,0. Avec csv.reader(fichier, delimiter=";"), quelle liste obtiens-tu ?

tout est lu comme texte ; la conversion en nombre est à faire soi-même (sortie vérifiée). La réponse c est ce que donne le séparateur ,.

2. Que fait le mode "w" dans open(chemin, "w") ?

"w" écrit à neuf ; on n'ouvre donc jamais les données brutes en "w".

3. À quoi sert with devant open ?

le fichier est refermé même si une erreur survient dans le bloc.
[6]Kit

🎒 Ton kit — Épisode 13

25 min

Exercice : du CSV au JSON

  1. Crée croissance.csv dans le dossier de ton script, avec l'en-tête et les 15 lignes (3 éclairages × 5 jours, valeurs de la semaine 2, virgule décimale, ; comme séparateur).
  2. Lis-le avec DictReader et reconstruis le dictionnaire de listes.
  3. Calcule la moyenne de chaque éclairage et écris resume.json.
  4. Relis resume.json avec json.load et vérifie une valeur.
  5. Teste un nom de fichier mal écrit et lis le message d'erreur.

Code à copier : la lecture avec DictReader ci-dessus.

Checklist

  • Je construis mes chemins avec pathlib.
  • J'ouvre mes fichiers avec with et un encodage.
  • Je lis un CSV français (séparateur ;, virgule décimale) et j'écris un JSON.
Vigilanceon ne modifie jamais le fichier de données brutes ; on écrit les résultats dans un autre fichier, et on garde une copie des données d'origine.
[7]Journal

✍️ Journal de bord

Quels fichiers de tes TP ou de tes cours pourrais-tu faire lire par un script (CSV de mesures, exports de tableur, listes) ?

[8]Sources
  1. Python Software Foundation, csv — Lecture et écriture de fichiers CSV, consulté le 30/10/2026.
  2. Python Software Foundation, json — Encodage et décodage JSON, consulté le 30/10/2026.
  3. Python Software Foundation, pathlib — Chemins de système de fichiers orientés objet, consulté le 30/10/2026.
  4. Real Python, Python 3.15 makes UTF-8 the default encoding (PEP 686), consulté le 30/10/2026.
14
S3 · JEUDI · Pratiquer

Installer des bibliothèques proprement

Un projet, un environnement : créer un environnement virtuel, y installer pandas et matplotlib, décrire ses dépendances.

⏱ 25 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Jeudi, 10 h

Le TP demande pandas (tableaux de données) et matplotlib (graphiques), qui ne sont pas fournis avec Python. Un tutoriel trouvé en ligne conseille sudo pip install pandas. Awa frissonne : « L'an dernier, j'ai fait ça. J'ai cassé le Python de mon ordinateur, et plus rien ne marchait. » Il y a une façon propre de faire.

[2]Méthode

« Un projet, un environnement »

Un paquet est une bibliothèque qu'on installe depuis PyPI, l'index officiel des paquets Python, avec l'outil pip. Un environnement virtuel est un dossier qui contient un Python et des paquets propres à un projet.

  1. Créer l'environnement, dans le dossier du TP : python -m venv .venv (sous Windows, py -m venv .venv fonctionne aussi).
  2. L'activer :
SystèmeCommande
macOS, Linux (bash, zsh)source .venv/bin/activate
Windows (invite de commandes).venv\Scripts\activate.bat
Windows (PowerShell).venv\Scripts\Activate.ps1

Le nom de l'environnement s'affiche alors devant l'invite. deactivate en sort.

  1. Installer dans l'environnement actif : python -m pip install pandas matplotlib. Vérifie le nom exact du paquet sur pypi.org avant d'installer.
  2. Lister et décrire : python -m pip list montre ce qui est installé ; python -m pip freeze > requirements.txt écrit la liste exacte des versions dans un fichier.
  3. Réinstaller ailleurs (chez ton binôme, sur l'ordinateur de l'enseignante) : créer un environnement, l'activer, puis python -m pip install -r requirements.txt.

Le requirements.txt réel obtenu le 30/10/2026 après python -m pip install pandas matplotlib (Python 3.15) :

Contenu de requirements.txt
contourpy==1.4.0 cycler==0.12.1 fonttools==4.68.0 kiwisolver==1.5.1 matplotlib==3.11.2 numpy==2.5.4 packaging==26.3 pandas==3.1.0 pillow==13.0.0 pyparsing==3.3.3 python-dateutil==3.0.0 six==1.17.0 tzdata==2026.6

Deux paquets demandés, treize installés : pandas et matplotlib s'appuient sur d'autres paquets (les dépendances), installés automatiquement.

Dans Thonny : menu Outils → Gérer les paquets (Tools → Manage packages) pour chercher et installer un paquet sans ligne de commande.

Sans rien installer : Basthon fournit déjà numpy, pandas et matplotlib dans le navigateur, et permet d'importer un fichier CSV. Capytale peut aussi les proposer, selon l'activité créée par ton professeur.

Auto-diagnostic · mon environnement est-il propre ?
  • Mon projet a son propre environnement virtuel.
  • Je l'active avant d'installer.
  • J'installe avec python -m pip, sans sudo.
  • J'ai vérifié le nom exact des paquets sur pypi.org.
  • Mon requirements.txt est à jour.
  • Le dossier .venv n'est pas partagé ni versionné.
[3]Pourquoi ça marche

Chaque projet garde ses propres versions : le TP de biologie peut utiliser pandas 3.1 sans gêner un autre projet. Casser un environnement ne casse ni Python ni le reste de l'ordinateur : on supprime le dossier .venv et on le recrée à partir de requirements.txt. Et ce fichier permet à ton enseignante de reproduire exactement ton environnement pour relancer ton TP.

À retenirun projet, un environnement ; activer avant d'installer ; vérifier le nom du paquet ; requirements.txt à jour.
[4]Entraînement

Bon réflexe ou piège ?

J'installe pandas pour tout le système avec sudo pip install.
tu risques de casser le Python de ton système et des programmes qui en dépendent.
Je tape un nom de paquet approximatif, pip trouvera bien.
des paquets malveillants imitent les noms des paquets connus ; vérifie l'orthographe sur pypi.org.
J'active l'environnement avant d'installer.
sinon, le paquet s'installe ailleurs que dans ton projet.
J'envoie mon dossier .venv à mon binôme.
il est lié à ton ordinateur ; envoie plutôt requirements.txt.
Après chaque installation, je mets à jour requirements.txt.
ton projet reste reproductible.
[5]Quiz

1. Que fait python -m venv .venv ?

il crée un dossier avec un Python et un espace pour les paquets propres au projet.

2. Tu as demandé pandas et matplotlib ; requirements.txt en liste treize. Pourquoi ?

numpy, pillow, python-dateutil… sont nécessaires à pandas et matplotlib (sortie réelle).

3. Comment ton binôme installe-t-il les mêmes versions que toi ?

le fichier fixe les versions exactes ; chacun crée son environnement chez soi.
[6]Kit

🎒 Ton kit — Épisode 14

25 min

Exercice : l'environnement du TP

  1. Dans le dossier du TP, crée un environnement virtuel et active-le.
  2. Installe pandas et matplotlib avec python -m pip.
  3. Vérifie avec python -m pip list, puis écris requirements.txt.
  4. Vérifie dans la console de l'environnement : import pandas, matplotlib puis print(pandas.__version__).
  5. Coche l'auto-diagnostic.

Code à copier : aucun ; ce sont des commandes de terminal (ou le gestionnaire de paquets de Thonny).

Checklist

  • Mon TP a son environnement virtuel.
  • pandas et matplotlib y sont installés.
  • Mon requirements.txt est écrit.
Vigilancesi tu es mineur, installe avec un adulte ; sur un ordinateur de l'établissement, suis les règles de la salle, ou travaille dans Basthon, qui ne demande aucune installation.
[7]Journal

✍️ Journal de bord

As-tu déjà « cassé » une installation de logiciel ? Qu'est-ce qu'un environnement virtuel aurait changé ?

[8]Sources
  1. Python Software Foundation, venv — Création d'environnements virtuels (commandes d'activation, environnement jetable non versionné), consulté le 30/10/2026.
  2. Commandes venv, pip install et pip freeze exécutées le 30/10/2026 avec Python 3.15.0 (journal de test de ce livre).
  3. TechTarget, Typosquatting campaign, malicious packages slam PyPI (mars 2024 : plus de 500 paquets malveillants aux noms imitant des paquets connus ; inscriptions suspendues une dizaine d'heures), consulté le 30/10/2026.
  4. Lycée du Val de Lys, Coder en Python dans le navigateur, Basthon (numpy, matplotlib, pandas intégrés ; import de fichiers CSV), consulté le 30/10/2026.
  5. It's FOSS, Thonny: An Ideal IDE for Teaching Python Programming in Schools, « Manage Pip from GUI », consulté le 30/10/2026.
15
S3 · VENDREDI · Pratiquer · Bilan d'arc

Fichiers et bibliothèques : le bilan

Ton outil de synthèse, le récapitulatif de la semaine et ton badge.

⏱ 20 min · arbre de décision · carrousel · quiz final
[1]Scénario
Yanis · Vendredi, 17 h

Yanis lance son script : il lit croissance.csv, calcule moyenne, médiane et écart type de chaque éclairage avec statistics, et écrit resume.json. Awa clone son dossier, crée son propre environnement à partir de requirements.txt, relance : même résultat. Lundi, il réinventait l'écart type ; aujourd'hui, son TP tourne sur un autre ordinateur que le sien.

[2]Outil

« Bibliothèque standard ou paquet à installer ? »

Aide à la décision interactive
[3]Carrousel

🎨 Carrousel récapitulatif — Semaine 3

[4]Quiz final

1. Que renvoie statistics.median([4, 1, 3, 2]) ?

moyenne des deux valeurs centrales, 2 et 3 (sortie vérifiée).

2. Un DictReader lit taille_mm = "12,0". Comment obtenir le nombre 12.0 ?

le texte contient une virgule décimale, que float refuse ; on la remplace d'abord.

3. Ton script ouvre resume.json en mode "w". Que devient l'ancien fichier ?

"w" réécrit le fichier à neuf.

4. Tu as besoin de pandas sur l'ordinateur de la bibliothèque universitaire, où tu ne peux rien installer. Que fais-tu ?

c'est la branche « je ne peux pas installer » de l'arbre de décision.

5. Que ne faut-il pas versionner ni envoyer à son binôme ?

l'environnement est propre à chaque ordinateur ; on partage requirements.txt pour le recréer.
[5]Kit

🎒 Ton kit de fin d'arc

25 min

Le TP lit son CSV et écrit son résumé

Synthèse : des chemins, un CSV lu, des statistiques standard, un JSON écrit.

Code à copier — tp_croissance.py, dans le même dossier que croissance.csv

Code à copier
"""TP croissance : lit croissance.csv, résume chaque éclairage, écrit resume.json."""

import csv
import json
import statistics
from pathlib import Path

DOSSIER = Path(__file__).parent
FICHIER_MESURES = DOSSIER / "croissance.csv"
FICHIER_RESUME = DOSSIER / "resume.json"


def lire_mesures(chemin):
    """Renvoie un dictionnaire {éclairage: [tailles en mm]} lu dans un CSV séparé par des « ; »."""
    mesures = {}
    with open(chemin, encoding="utf-8") as fichier:
        for ligne in csv.DictReader(fichier, delimiter=";"):
            taille = float(ligne["taille_mm"].replace(",", "."))
            eclairage = ligne["eclairage"]
            if eclairage not in mesures:
                mesures[eclairage] = []
            mesures[eclairage].append(taille)
    return mesures


def resumer(serie):
    """Renvoie un dictionnaire de résumé d'une série non vide."""
    return {
        "n": len(serie),
        "moyenne": round(statistics.mean(serie), 2),
        "mediane": statistics.median(serie),
        "ecart_type": round(statistics.stdev(serie), 2),
        "min": min(serie),
        "max": max(serie),
    }


mesures = lire_mesures(FICHIER_MESURES)
resume = {}
for eclairage, serie in mesures.items():
    resume[eclairage] = resumer(serie)
with open(FICHIER_RESUME, "w", encoding="utf-8") as fichier:
    json.dump(resume, fichier, ensure_ascii=False, indent=2)
for eclairage, valeurs in resume.items():
    print(f"{eclairage:<8} n={valeurs['n']}  moyenne={valeurs['moyenne']:>6.2f}  écart type={valeurs['ecart_type']:>5.2f}")
print(f"Résumé écrit dans {FICHIER_RESUME.name}")

Sortie réelle :

Ce que tu vois
bleue n=5 moyenne= 17.20 écart type= 4.28 rouge n=5 moyenne= 13.60 écart type= 2.10 blanche n=5 moyenne= 18.40 écart type= 4.92 Résumé écrit dans resume.json

Le fichier resume.json contient, pour chaque éclairage, l'effectif, la moyenne, la médiane, l'écart type, le minimum et le maximum (par exemple, pour « bleue » : "mediane": 17.0, "ecart_type": 4.28). Une docstring en tête du fichier dit à quoi il sert.

Consigne : lance le script dans l'environnement de ton TP ; ouvre resume.json pour le vérifier ; ajoute une ligne de mesures au CSV, relance, et constate que le résumé suit. Puis exporte ton carnet de bord (bouton dans le menu).

Checklist

  • J'ai exporté mon carnet (bouton dans le menu).
  • Mon TP lit le CSV et écrit resume.json.
  • Mon environnement est décrit dans requirements.txt.
[6]Journal

✍️ Journal de bord — bilan

Ton TP tourne maintenant sur un autre ordinateur que le tien. Qu'est-ce qui, cette semaine, l'a rendu possible ?

✦ GARDIENNE · GARDIEN DES FICHIERS · SEMAINE 3 ✦

Bravo ! Tu as terminé la semaine 3. Tu sais utiliser la bibliothèque standard et sa documentation, lire et écrire des fichiers CSV et JSON, et installer des bibliothèques dans un environnement propre.

ARC 4 · SEMAINE 4

Analyser et versionner

Cette semaine, tu analyses tes mesures avec pandas, tu traces les figures de ton compte rendu, tu gardes l'historique de ton travail avec Git et tu apprends à te faire aider par une IA sans tricher. Vendredi, tu rends un TP complet, versionné, que ton enseignante peut relancer.

16
S4 · LUNDI · Comprendre

Tableaux de données et graphiques

Lire un CSV dans un tableau pandas, sélectionner, filtrer, grouper, résumer, puis tracer une courbe avec matplotlib.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Lundi, 9 h

Awa ouvre son ordinateur : « Regarde. » Cinq lignes de pandas, et le résumé par éclairage s'affiche, celui qui a pris trois semaines à Yanis. Il est vexé. Puis il lit les lignes une par une et se rend compte qu'il comprend chacune : la virgule décimale, l'écart type d'échantillon, le regroupement par éclairage. « Ces cinq lignes font ce que mon script fait. Sauf que maintenant, je sais ce qu'elles font. »

[2]Concept

pandas et matplotlib

pandas range des données dans un DataFrame : un tableau avec des lignes numérotées (l'index) et des colonnes nommées, chacune avec son type. matplotlib trace des graphiques. Les deux sont installés dans l'environnement du TP (épisode 14).

Lire le CSV du TP.

Code
import pandas as pd

df = pd.read_csv("croissance.csv", sep=";", decimal=",")
print(df.shape)
print(df.head(4))
print(df.dtypes)

Affiche :

Ce que tu vois
(15, 3) jour eclairage taille_mm 0 J1 bleue 12.0 1 J2 bleue 14.5 2 J3 bleue 17.0 3 J4 bleue 19.5 jour str eclairage str taille_mm float64 dtype: object

sep=";" donne le séparateur, decimal="," la virgule décimale : taille_mm est directement un nombre à virgule (float64), sans replace (comparer avec épisode 13). shape donne (lignes, colonnes) ; head(4) les 4 premières lignes. pd est l'alias habituel de pandas (voir épisode 11). Depuis pandas 3.0, les colonnes de texte ont le type str ; dans une version plus ancienne, tu verras object.

Sélectionner et filtrer.

Code
print(df["taille_mm"].max())
rouge = df[df["eclairage"] == "rouge"]
print(rouge)
print(df[df["taille_mm"] > 20])

Affiche :

Ce que tu vois
25.0 jour eclairage taille_mm 5 J1 rouge 11.0 6 J2 rouge 12.5 7 J3 rouge 13.0 8 J4 rouge 15.5 9 J5 rouge 16.0 jour eclairage taille_mm 4 J5 bleue 23.0 13 J4 blanche 21.0 14 J5 blanche 25.0

df["taille_mm"] est une colonne ; df[["jour", "taille_mm"]] (doubles crochets) en garde plusieurs. df[condition] garde les lignes où la condition est vraie : c'est un filtre. Les lignes gardent leur numéro d'origine.

Grouper et résumer.

Code
moyennes = df.groupby("eclairage")["taille_mm"].mean()
print(moyennes)
print(df.groupby("eclairage", sort=False)["taille_mm"].describe().round(2))

Affiche :

Ce que tu vois
eclairage blanche 18.4 bleue 17.2 rouge 13.6 Name: taille_mm, dtype: float64 count mean std min 25% 50% 75% max eclairage bleue 5.0 17.2 4.28 12.0 14.5 17.0 19.5 23.0 rouge 5.0 13.6 2.10 11.0 12.5 13.0 15.5 16.0 blanche 5.0 18.4 4.92 12.5 15.0 18.5 21.0 25.0

groupby découpe le tableau par éclairage, applique le calcul à chaque groupe, puis rassemble les résultats. Par défaut, les groupes sont triés par ordre alphabétique ; sort=False garde l'ordre du fichier. describe donne l'effectif, la moyenne, l'écart type (std, d'échantillon : les mêmes 4,28 qu'avec statistics.stdev), le minimum, les quartiles (25 %, 50 % = la médiane, 75 %) et le maximum. Tu retrouves exactement le résumé de la semaine 3 : c'est ton cas connu pour vérifier pandas.

Tracer une courbe.

Code
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv("croissance.csv", sep=";", decimal=",")
for eclairage, groupe in df.groupby("eclairage", sort=False):
    plt.plot(groupe["jour"], groupe["taille_mm"], marker="o", label=eclairage)
plt.title("Croissance des plantules selon l'éclairage")
plt.xlabel("Jour de mesure")
plt.ylabel("Taille (mm)")
plt.legend()
plt.savefig("croissance.png")
print("Figure enregistrée : croissance.png")

Affiche Figure enregistrée : croissance.png, et le fichier image apparaît dans le dossier. Parcourir un groupby donne des couples (nom du groupe, sous-tableau). plt.plot(x, y) trace une courbe ; plt.bar(x, hauteurs) un diagramme en barres ; label + plt.legend() affichent la légende ; plt.savefig enregistre l'image (plt.show() l'afficherait dans une fenêtre).

Pour…pandas / matplotlib
lire un CSV « à la française »pd.read_csv(chemin, sep=";", decimal=",")
une colonne, plusieurs colonnesdf["col"], df[["col1", "col2"]]
filtrer des lignesdf[df["col"] == valeur]
un résumé par groupedf.groupby("groupe")["col"].mean() ou .describe()
une courbe, des barresplt.plot(x, y), plt.bar(x, hauteurs)
titre, axes, légendeplt.title, plt.xlabel, plt.ylabel, plt.legend()
enregistrerplt.savefig("nom.png")

Lire un graphique d'un œil critique. Avant de croire un graphique : de quoi parle-t-il (titre) ? Quelles grandeurs et quelles unités (axes) ? Où commence l'axe vertical ? Les courbes ou les barres sont-elles identifiées (légende) ? Demain, tu appliques ces questions à tes propres figures.

Autres outils. Polars est une autre bibliothèque de tableaux de données ; les notebooks (Jupyter) mélangent code, résultats et texte. Ce livre s'en tient à pandas et à des scripts.

Du tableau au graphique · les 15 mesures du TP
Série :
Graphique :
Le code matplotlib correspondant

[3]Recherche

Ce que disent les sources

  • Documentation officielle de pandas (version 3.1.0) — groupby suit le schéma « découper, appliquer, combiner » : il découpe le tableau en groupes, applique une fonction à chacun et combine les résultats ; par défaut, les clés de groupe sont triées [1].
  • Annonce de pandas 3.0 — Les colonnes de texte sont désormais reconnues avec le nouveau type str au lieu de object (version 3.0.0 publiée le 21 janvier 2026) [2].
  • Documentation officielle de matplotlib (version 3.11.2) — savefig enregistre la figure courante ; le paramètre dpi règle sa résolution en points par pouce [3].
  • Tests de ce livre — describe donne pour la lumière bleue un écart type de 4,28, identique à statistics.stdev (épisode 11), sous Python 3.12.13 comme sous 3.15.0, avec pandas 3.1.0 (journal de test).
[4]Mythes
« Avec pandas, plus besoin de comprendre ses données. »
pandas calcule vite, mais c'est toi qui choisis le séparateur, la colonne, le calcul ; et tu vérifies sur un cas connu, comme le résumé de la semaine 3.
« Un graphique, c'est de la décoration. »
c'est souvent la première chose que lit un correcteur ; un graphique sans titre ni unité ne répond à aucune question.
« Plus il y a de couleurs, plus c'est clair. »
une couleur par série, expliquée par la légende, suffit ; les autres couleurs n'apportent que du bruit.
[5]Quiz

1. Dans croissance.csv, les tailles s'écrivent 12,0. Quels paramètres de read_csv donnent des nombres à virgule ?

le séparateur de colonnes est ;, la virgule est le séparateur décimal ; il faut les deux.

2. Que renvoie df[df["taille_mm"] > 20] ?

c'est un filtre ; ici 3 lignes (sortie vérifiée).

3. Pourquoi groupby("eclairage") affiche-t-il « blanche » en premier ?

par défaut, les clés sont triées ; sort=False garde l'ordre du fichier.
[6]Kit

🎒 Ton kit — Épisode 16

20 min

Exercice : le résumé de la semaine 3 en pandas

  1. Dans l'environnement du TP, lis croissance.csv avec pd.read_csv et affiche shape, head() et dtypes.
  2. Affiche seulement les mesures du jour 5.
  3. Calcule la moyenne par éclairage avec groupby et compare-la avec resume.json (semaine 3) : les valeurs doivent être identiques.
  4. Trace la courbe de croissance des trois éclairages et enregistre-la.

Code à copier : les quatre programmes du concept.

Checklist

  • Je lis un CSV « à la française » avec read_csv.
  • Je sais sélectionner une colonne et filtrer des lignes.
  • J'ai retrouvé le résumé de la semaine 3 avec groupby.
  • J'ai enregistré une courbe avec titre, axes et légende.
Vigilanceun résultat de pandas se vérifie comme un autre : compare-le à un cas que tu connais.
[7]Journal

✍️ Journal de bord

Quelle ligne de pandas t'aurait le plus fait gagner de temps en semaine 3 ? Et qu'est-ce que la semaine 3 t'a appris que pandas ne t'aurait pas appris ?

[8]Sources
  1. pandas, pandas.DataFrame.groupby, documentation de la version 3.1.0, consulté le 30/10/2026.
  2. pandas, pandas 3.0 released! et What's new in 3.0.0 (January 21, 2026), consulté le 30/10/2026.
  3. Matplotlib, matplotlib.pyplot.savefig, documentation de la version 3.11.2, consulté le 30/10/2026.
17
S4 · MARDI · Pratiquer

Le graphique qui répond à la question

Une question, une figure : titre, axes avec unités, légende, échelle honnête, enregistrement dans un dossier figures/.

⏱ 25 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Mardi, 16 h

Yanis montre sa première figure à Awa : trois barres bleues, sans titre, sans unité, sans légende. La barre de la lumière rouge est minuscule, dix fois plus petite que celle de la lumière blanche. « Le rouge bloque la croissance ! » Awa regarde l'axe vertical : il commence à 15 mm. En vrai, les plantules sous lumière rouge mesurent 16 mm au jour 5, contre 25 mm sous lumière blanche : environ les deux tiers, pas un dixième.

[2]Méthode

« Une question, une figure »

  1. Écrire la question à laquelle la figure répond, en une phrase. Elle deviendra le titre, ou presque.
  2. Choisir le type : une évolution dans le temps → une courbe ; une comparaison entre catégories → des barres ; jamais un camembert pour une évolution.
  3. Étiqueter : un titre, chaque axe avec sa grandeur et son unité, une légende dès qu'il y a plusieurs séries, une couleur par série.
  4. Vérifier l'échelle : un diagramme en barres part de zéro (plt.ylim(0, …)), sinon les différences paraissent plus grandes qu'elles ne sont. Une courbe peut ne pas partir de zéro, si l'axe est bien gradué.
  5. Enregistrer dans un dossier figures/, en PNG, avec une résolution suffisante (dpi=200) et sans marges inutiles (bbox_inches="tight"). plt.figure() commence une nouvelle figure, plt.close() la ferme.

La figure fautive de Yanis (le code qui l'a produite) :

Code
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv("croissance.csv", sep=";", decimal=",")
finales = df[df["jour"] == "J5"]
plt.bar(finales["eclairage"], finales["taille_mm"])
plt.ylim(15, 26)
plt.savefig("mauvais.png")
print("rouge / blanche, vraies tailles :", round(16.0 / 25.0, 2))

Affiche rouge / blanche, vraies tailles : 0.64. Sur l'image, la barre rouge ne monte que de 1 mm au-dessus du bas de l'axe, contre 10 mm pour la blanche : elle paraît dix fois plus petite.

Les deux figures du TP — figures_tp.py, dans le dossier du TP :

Code
"""Trace les deux figures du compte rendu dans le dossier figures/."""

from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd

DOSSIER = Path(__file__).parent
FIGURES = DOSSIER / "figures"
FIGURES.mkdir(exist_ok=True)
COULEURS = {"bleue": "tab:blue", "rouge": "tab:red", "blanche": "tab:gray"}

df = pd.read_csv(DOSSIER / "croissance.csv", sep=";", decimal=",")

# Figure 1 — Question : comment la taille évolue-t-elle, jour après jour, sous chaque éclairage ?
plt.figure()
for eclairage, groupe in df.groupby("eclairage", sort=False):
    plt.plot(groupe["jour"], groupe["taille_mm"], marker="o",
             color=COULEURS[eclairage], label=f"lumière {eclairage}")
plt.title("Croissance des plantules selon l'éclairage (J1 à J5)")
plt.xlabel("Jour de mesure")
plt.ylabel("Taille (mm)")
plt.legend()
plt.savefig(FIGURES / "evolution.png", dpi=200, bbox_inches="tight")
plt.close()

# Figure 2 — Question : quel éclairage donne les plus grandes plantules au jour 5 ?
finales = df[df["jour"] == "J5"]
plt.figure()
plt.bar(finales["eclairage"], finales["taille_mm"],
        color=[COULEURS[e] for e in finales["eclairage"]])
plt.title("Taille des plantules au jour 5, par éclairage")
plt.xlabel("Éclairage")
plt.ylabel("Taille au jour 5 (mm)")
plt.ylim(0, 30)
plt.savefig(FIGURES / "taille_j5.png", dpi=200, bbox_inches="tight")
plt.close()

print(finales)
for fichier in sorted(FIGURES.iterdir()):
    print("Enregistrée :", fichier.name)

Sortie réelle :

Ce que tu vois
jour eclairage taille_mm 4 J5 bleue 23.0 9 J5 rouge 16.0 14 J5 blanche 25.0 Enregistrée : evolution.png Enregistrée : taille_j5.png

Les couleurs reprennent celles des éclairages (gris pour le blanc, qui serait invisible sur fond blanc). FIGURES.mkdir(exist_ok=True) crée le dossier s'il n'existe pas encore ; iterdir() en parcourt le contenu. Le tableau affiché sert de cas connu : les hauteurs des barres doivent être 23, 16 et 25.

Figure 1 : croissance des plantules selon l'éclairage, de J1 à J5 (image réelle produite par figures_tp.py).
Figure 1 : croissance des plantules selon l'éclairage, de J1 à J5 (image réelle produite par figures_tp.py).
Figure 2 : taille des plantules au jour 5, barres partant de zéro (image réelle produite par figures_tp.py).
Figure 2 : taille des plantules au jour 5, barres partant de zéro (image réelle produite par figures_tp.py).
[3]Pourquoi ça marche

Une figure qui part d'une question se lit en quelques secondes : le titre dit ce qu'elle montre, les axes disent avec quelles grandeurs, la légende dit qui est qui. L'axe à zéro pour les barres protège ton lecteur… et ta conclusion : la longueur d'une barre est proportionnelle à la valeur. Enregistrer par le code, dans figures/, permet de régénérer toutes les figures en une commande quand une mesure change.

À retenirune question, une figure ; titre, axes avec unités, légende ; barres à partir de zéro ; enregistrées par le code.
[4]Entraînement

Bon réflexe ou piège ?

Mon diagramme en barres commence à 15 mm, ça fait ressortir les écarts.
les écarts paraissent bien plus grands qu'ils ne sont ; un diagramme en barres part de zéro.
J'écris l'unité sur chaque axe : “Taille (mm)”.
sans unité, 16 peut être des millimètres ou des centimètres.
Je trace l'évolution de la taille en camembert.
un camembert montre les parts d'un tout, pas une évolution ; il faut une courbe.
Trois séries, trois couleurs, et une légende.
chaque courbe est identifiée sans deviner.
Je fais une capture d'écran de la fenêtre du graphique pour mon compte rendu.
l'image est floue et à refaire à chaque changement ; savefig avec dpi=200 la régénère nette.
[5]Quiz

1. Tu compares la taille au jour 5 sous trois éclairages. Quel graphique ?

une comparaison entre catégories se lit avec des barres, dont la longueur doit être proportionnelle à la valeur.

2. Que fait plt.ylim(0, 30) ?

il règle les limites de l'axe des ordonnées.

3. Pourquoi plt.close() après chaque savefig ?

chaque figure commence par plt.figure() et se ferme une fois enregistrée.
[6]Kit

🎒 Ton kit — Épisode 17

25 min

Exercice : les figures du TP

  1. Écris, en commentaire, la question de chacune de tes deux figures.
  2. Lance figures_tp.py dans l'environnement du TP et ouvre les deux images.
  3. Relis-les comme un correcteur : titre ? axes et unités ? légende ? échelle ?
  4. Lance la figure fautive, compare, et explique en une phrase ce qui trompe.

Code à copier : figures_tp.py (ci-dessus).

Checklist

  • Chaque figure répond à une question écrite.
  • Titre, axes avec unités, légende.
  • Les barres partent de zéro.
  • Les figures sont enregistrées dans figures/ par le code.
Vigilancen'ajuste jamais un axe pour « faire ressortir » le résultat que tu espères.
[7]Journal

✍️ Journal de bord

As-tu déjà été convaincu par un graphique (dans un article, une publicité) dont l'axe ne partait pas de zéro ? Qu'aurait-il montré avec un axe honnête ?

[8]Sources
  1. Matplotlib, matplotlib.pyplot.savefig (paramètres dpi et bbox_inches), documentation de la version 3.11.2, consulté le 30/10/2026.
  2. Programme exécuté le 30/10/2026 avec Python 3.12.13 et 3.15.0, pandas 3.1.0 et matplotlib 3.11.2 ; images vérifiées (journal de test de ce livre).
18
S4 · MERCREDI · Comprendre

Versionner ton travail avec Git

Un dépôt, des commits, un historique : garder chaque version de ton TP, puis le partager avec un dépôt distant.

⏱ 20 min de lecture · 5 min de quiz
[1]Scénario
Yanis · Mercredi, 11 h

Dans le dossier du TP : tp_final.py, tp_final2.py, tp_final_VRAI.py, tp_final_VRAI_awa.py. La version d'hier, celle qui marchait, a disparu sous une modification de trop. Et le sujet précise : « Le TP est rendu sous la forme d'un lien vers un dépôt. » Yanis : « Un dépôt de quoi ? »

[2]Concept

Git, dépôts et commits

Git est un logiciel de gestion de versions : il garde l'historique de tes fichiers. Un dépôt est un dossier suivi par Git (il contient un dossier caché .git). Un commit est une photo de tes fichiers à un instant, avec un message qui dit ce qui a changé. Git s'installe depuis son site officiel (git-scm.com) ; dans Thonny ou VS Code, il s'utilise aussi depuis le terminal.

Le cycle en trois zones. Tu modifies un fichier dans ton dossier de travail ; git add le place dans l'index (ce qui partira dans le prochain commit) ; git commit enregistre la photo dans l'historique.

La démonstration réelle (dossier du TP, identité inventée) :

Dans le terminal
$ git init -b main Initialized empty Git repository in tp-croissance/.git/ $ git config user.name "Yanis" $ git config user.email "yanis@example.org" $ git status On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) .venv/ __pycache__/ croissance.csv requirements.txt tp_croissance.py

git init crée le dépôt (-b main nomme la ligne principale de l'historique main, comme sur les services en ligne). git config donne le nom et l'adresse inscrits dans chaque commit : sur un dépôt public, tout le monde les voit ; choisis ce que tu acceptes de montrer. git status dit où en est chaque fichier : ici, tous sont « non suivis » (untracked). Selon la langue de ton système, Git peut afficher ces messages en français.

Ce qu'on ne versionne pas : .gitignore. Un fichier texte .gitignore liste ce que Git doit ignorer :

Contenu de .gitignore
.venv/ __pycache__/

L'environnement virtuel se recrée avec requirements.txt (épisode 14) ; __pycache__ est fabriqué par Python. Jamais de mot de passe, de clé, ni de données personnelles dans un dépôt : même effacés plus tard, ils restent dans l'historique.

Dans le terminal
$ git status --short ?? .gitignore ?? croissance.csv ?? requirements.txt ?? tp_croissance.py $ git add .gitignore croissance.csv tp_croissance.py requirements.txt $ git status --short A .gitignore A croissance.csv A requirements.txt A tp_croissance.py $ git commit -m "Lit les mesures et écrit le résumé JSON" [main (root-commit) 8079c3c] Lit les mesures et écrit le résumé JSON 4 files changed, 67 insertions(+) create mode 100644 .gitignore create mode 100644 croissance.csv create mode 100644 requirements.txt create mode 100644 tp_croissance.py

?? = non suivi ; A = ajouté à l'index ; .venv/ et __pycache__/ ont disparu de la liste. 8079c3c est le début de l'identifiant du commit ; chez toi, il sera différent.

Voir ce qui a changé, puis l'historique. Yanis modifie la dernière ligne de son script :

Dans le terminal
$ git status --short M tp_croissance.py $ git diff diff --git a/tp_croissance.py b/tp_croissance.py index a5c461b..745d1a2 100644 --- a/tp_croissance.py +++ b/tp_croissance.py @@ -43,4 +43,4 @@ with open(FICHIER_RESUME, "w", encoding="utf-8") as fichier: json.dump(resume, fichier, ensure_ascii=False, indent=2) for eclairage, valeurs in resume.items(): print(f"{eclairage:<8} n={valeurs['n']} moyenne={valeurs['moyenne']:>6.2f} écart type={valeurs['ecart_type']:>5.2f}") -print(f"Résumé écrit dans {FICHIER_RESUME.name}") +print(f"Résumé écrit dans {FICHIER_RESUME.name} ({len(resume)} éclairages)") $ git add tp_croissance.py $ git commit -m "Affiche le nombre d'éclairages résumés" [main 54b0142] Affiche le nombre d'éclairages résumés 1 file changed, 1 insertion(+), 1 deletion(-) $ git log --oneline 54b0142 Affiche le nombre d'éclairages résumés 8079c3c Lit les mesures et écrit le résumé JSON

M = modifié ; git diff montre les lignes retirées (-) et ajoutées (+) depuis le dernier commit ; git log liste les commits, du plus récent au plus ancien (git log -1 détaille le dernier : auteur, date, message).

Un bon message de commit dit ce que fait le changement, en une phrase courte : « Corrige l'écart type (stdev au lieu de pstdev) » plutôt que « modif » ou « ça marche enfin ». Un commit = un changement qui a un sens, testé.

Le dépôt distant. Un dépôt distant est une copie de ton dépôt sur un service en ligne : GitHub, GitLab ou Codeberg, par exemple. Git n'est pas GitHub : Git est le logiciel, sur ton ordinateur ; ces services hébergent des dépôts. Démonstration réelle, avec un dépôt distant simulé dans un dossier voisin (sur un service, tu remplaces ../distant.git par l'adresse donnée par le service) :

Dans le terminal
$ git remote add origin ../distant.git $ git remote -v origin ../distant.git (fetch) origin ../distant.git (push) $ git push -u origin main To ../distant.git * [new branch] main -> main branch 'main' set up to track 'origin/main'. $ git clone distant.git copie-awa Cloning into 'copie-awa'... done. $ ls copie-awa croissance.csv requirements.txt tp_croissance.py

git remote add enregistre l'adresse du dépôt distant sous le nom origin ; git push y envoie tes commits ; git clone crée une copie complète, avec tout l'historique : c'est ce que fera ton enseignante. Ensuite, après chaque commit, un simple git push suffit. La première fois, le service te demande de te connecter : suis sa page d'aide.

Avant de créer un compte. GitHub demande d'avoir au moins 13 ans (et plus si la loi de ton pays l'exige) ; les conditions d'utilisation de Codeberg ne fixent pas d'âge minimum ; lis celles de GitLab avant de t'inscrire. Si tu es mineur, crée ton compte avec un adulte ; ton enseignant ou ton établissement peut aussi te fournir un espace. Choisis un dépôt privé tant que ton TP n'est pas rendu, sauf consigne contraire : un dépôt public est visible de tous, copie comprise.

Simulateur de commits · dossier tp-croissance
Dossier de travail
Index (prochain commit)
Historique
git status --short
[3]Recherche

Ce que disent les sources

  • Pro Git (en français), section 2.2 — Chaque fichier du dossier de travail est suivi ou non suivi ; git add indexe un fichier, git commit enregistre l'instantané de l'index ; un fichier .gitignore liste les fichiers à ne pas suivre [1].
  • Pro Git, sections 2.3 et 2.5 — git log affiche les commits du plus récent au plus ancien ; git remote add ajoute un dépôt distant, git push y pousse les commits, git clone copie un dépôt avec tout son historique [1].
  • Conditions d'utilisation de GitHub (en vigueur le 27 avril 2026) — « You must be age 13 or older » (« Vous devez avoir 13 ans ou plus ») ; dans certains pays, l'âge minimum légal peut être plus élevé [2].
  • Conditions d'utilisation de Codeberg — Elles ne fixent pas d'âge minimum (copie du 10/10/2026) [3].
  • Tests de ce livre — Toutes les commandes ci-dessus ont été exécutées le 30/10/2026 avec Git 2.43.0, dans un dossier jetable, avec une identité inventée (journal de test).
[4]Mythes
« Git, c'est GitHub. »
Git est un logiciel installé sur ton ordinateur, qui marche sans Internet ; GitHub, GitLab et Codeberg sont des services qui hébergent des dépôts.
« On commite une fois, à la fin. »
un commit par changement qui a un sens ; c'est ce qui permet de retrouver la version d'hier.
« Un dépôt public, c'est sans risque. »
tout le monde peut le lire et le copier, historique compris ; un mot de passe commité un jour y reste, même effacé ensuite.
[5]Quiz

1. Tu as modifié tp_croissance.py. Que fait git add tp_croissance.py ?

add prépare, commit enregistre, push envoie.

2. Que faut-il mettre dans .gitignore pour le TP ?

l'environnement se recrée avec requirements.txt, qui, lui, doit être versionné.

3. Quel est le meilleur message de commit ?

il dit ce que fait le changement ; dans trois semaines, tu sauras le retrouver.
[6]Kit

🎒 Ton kit — Épisode 18

20 min

Exercice : le dépôt du TP

  1. Dans le dossier du TP, crée le dépôt (git init -b main) et configure ton nom et ton adresse.
  2. Écris le .gitignore (.venv/, __pycache__/), puis vérifie avec git status.
  3. Fais 3 commits : le script et les données ; les figures (figures_tp.py) ; une petite amélioration. Un message utile à chaque fois.
  4. Consulte git log --oneline et git diff avant ton troisième commit.
  5. Si ton enseignant le demande, et après avoir lu les conditions d'âge du service (avec un adulte si tu es mineur) : crée un dépôt distant privé et pousse ton travail.

Code à copier : aucun ; ce sont des commandes de terminal.

Checklist

  • Mon TP est un dépôt Git, avec un .gitignore.
  • J'ai fait 3 commits avec des messages utiles.
  • Je sais lire git status, git diff et git log.
  • Aucun mot de passe ni donnée personnelle n'est versionné.
Vigilanceavant le premier git add, vérifie avec git status qu'aucun fichier sensible n'est dans la liste.
[7]Journal

✍️ Journal de bord

Combien de fichiers « final », « final2 », « VRAI » as-tu déjà eus dans un dossier ? Qu'aurais-tu gagné avec un historique de commits ?

[8]Sources
  1. Scott Chacon et Ben Straub, Pro Git, 2e édition en français, sections 2.2 « Enregistrer des modifications dans le dépôt », 2.3 « Visualiser l'historique des validations » et 2.5 « Travailler avec des dépôts distants » (git-scm.com/book/fr/v2, licence CC BY-NC-SA 3.0), consulté le 30/10/2026.
  2. GitHub, GitHub Terms of Service, section B « Account Terms » (en vigueur le 27 avril 2026), consulté le 30/10/2026.
  3. Codeberg e.V., Terms of Use (copie du 10/10/2026 par TOS Tracker), consulté le 30/10/2026.
  4. Commandes Git exécutées le 30/10/2026 avec Git 2.43.0, dossier jetable et identité inventée (journal de test de ce livre).
19
S4 · JEUDI · Pratiquer

Coder avec une IA : demander, relire, tester, déclarer

Se faire aider par un assistant d'IA sans renoncer à comprendre, dans le respect des conditions d'âge et des règles de ton cours.

⏱ 25 min de pratique · 5 min de quiz
[1]Scénario
Yanis · Jeudi, 22 h

Yanis veut une fonction qui trace les barres du jour 5. Il demande à un assistant d'IA, qui répond en dix lignes. Il lance : la figure apparaît, parfaite. Le lendemain matin, son script de la semaine 3 s'arrête sur KeyError: 'taille_mm'. Le fichier croissance.csv a changé : il est maintenant séparé par des virgules. Personne ne l'a ouvert… sauf la fonction de l'assistant. Heureusement, le fichier d'origine est dans le dépôt Git.

[2]Méthode

« Avant, demander, relire, tester, déclarer »

  1. Avant : vérifie que tu as le droit. Les règles de ton cours d'abord : l'IA est-elle autorisée pour ce TP, et pour quoi faire ? Les conditions d'âge du service ensuite :
AssistantÂge minimum (conditions vérifiées en octobre 2026)
ChatGPT (OpenAI)13 ans ; entre 13 et 18 ans, avec l'accord d'un parent
Claude (Anthropic)18 ans
Vibe (Mistral AI, ex-Le Chat)13 ans ; un mineur a besoin de l'accord d'un parent pour créer un compte
Gemini (Google), compte personnel13 ans, ou l'âge applicable dans ton pays

Tu n'as pas l'âge requis, ou pas l'accord nécessaire ? Fais l'exercice avec la réponse d'assistant fournie ci-dessous : la méthode est la même. Au lycée, on ne doit pas te demander de créer un compte personnel sur un service d'IA grand public.

  1. Demander : le contexte (Python, pandas, ton fichier), le but, les contraintes (« ne modifie pas le fichier de mesures »), un exemple d'entrée et de sortie attendue. Jamais de données personnelles, ni de sujet d'examen confidentiel, ni ton code entier si une fonction suffit. Demander une explication (« pourquoi ma barre est-elle décalée ? ») apprend plus que demander la solution.
  2. Relire : chaque ligne doit être comprise ; chasse ce que tu n'as pas demandé, surtout ce qui écrit, supprime ou envoie quelque chose (un fichier, Internet). Une ligne inconnue ? Cherche-la dans la documentation (épisode 12), ou ne la garde pas.
  3. Tester : sur un cas connu (les hauteurs 23, 16, 25), sur une copie des données, et vérifie que rien d'autre n'a changé.
  4. Déclarer : ce que tu as demandé, ce que tu as gardé, ce que tu as modifié.

La réponse d'assistant fournie par le livre (inventée pour l'exercice, typique de ce qu'on obtient) :

Code
import pandas as pd
import matplotlib.pyplot as plt


def tracer_barres(fichier):
    df = pd.read_csv(fichier, sep=";", decimal=",")
    df = df.dropna()
    df.to_csv(fichier, index=False)
    finales = df[df["jour"] == "J5"]
    plt.bar(finales["eclairage"], finales["taille_mm"])
    plt.savefig("barres.png")


tracer_barres("croissance.csv")

Lancée sur une copie du dossier, elle n'affiche rien, produit une belle figure… et réécrit le fichier de mesures. Avant, puis après :

Début du fichier croissance.csv
jour;eclairage;taille_mm J1;bleue;12,0
Début du fichier croissance.csv
jour,eclairage,taille_mm J1,bleue,12.0

Le script de la semaine 3 s'arrête alors :

Message d'erreur
Traceback (most recent call last): File "e15_tp.py", line 38, in <module> mesures = lire_mesures(FICHIER_MESURES) File "e15_tp.py", line 18, in lire_mesures taille = float(ligne["taille_mm"].replace(",", ".")) ~~~~~^^^^^^^^^^^^^ KeyError: 'taille_mm'

À la relecture : df.to_csv(fichier, index=False) écrit dans le fichier de mesures, avec la virgule comme séparateur ; personne ne l'a demandé. dropna() supprime les lignes incomplètes (NA : valeur manquante) sans le dire. Il manque aussi le titre, les axes, les unités, la docstring.

La version relue, corrigée et testée :

Code
from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd


def tracer_barres(fichier, image):
    """Trace la taille au jour 5 par éclairage et l'enregistre ; ne modifie pas le fichier de mesures."""
    df = pd.read_csv(fichier, sep=";", decimal=",")
    finales = df[df["jour"] == "J5"]
    plt.figure()
    plt.bar(finales["eclairage"], finales["taille_mm"])
    plt.title("Taille des plantules au jour 5, par éclairage")
    plt.xlabel("Éclairage")
    plt.ylabel("Taille au jour 5 (mm)")
    plt.ylim(0, 30)
    plt.savefig(image, dpi=200, bbox_inches="tight")
    plt.close()
    return list(finales["taille_mm"])


avant = Path("croissance.csv").read_text(encoding="utf-8")
hauteurs = tracer_barres("croissance.csv", "barres.png")
print(hauteurs)
assert hauteurs == [23.0, 16.0, 25.0]
assert Path("croissance.csv").read_text(encoding="utf-8") == avant
print("Tests : hauteurs justes, fichier de mesures intact")

Sortie réelle :

Ce que tu vois
[23.0, 16.0, 25.0] Tests : hauteurs justes, fichier de mesures intact

La fonction renvoie les hauteurs tracées : on peut les tester. Le second test vérifie que le fichier n'a pas changé (read_text lit tout le fichier d'un coup).

La déclaration d'aide, à mettre dans le compte rendu, sous forme de tableau :

OutilUsagePassage concernéCe que j'en ai fait
Assistant d'IA (nom, date)Proposer une fonction de diagramme en barrestracer_barres dans figures_tp.pyRelue ; supprimé l'écriture dans le CSV et dropna ; ajouté titre, axes, docstring et tests
Auto-diagnostic · avant de garder un code proposé par une IA
  • L'IA est autorisée pour ce travail et j'ai l'âge (ou l'accord) requis par le service.
  • Ma demande ne contenait ni donnée personnelle ni sujet confidentiel.
  • Je comprends chaque ligne.
  • Le code ne lit, n'écrit, ne supprime et n'envoie rien que je n'ai pas demandé.
  • Je l'ai testé sur un cas connu, sur une copie des données.
  • J'ai rédigé la déclaration d'aide.
[3]Pourquoi ça marche

La règle d'or du Boost reste vraie : un code que tu ne comprends pas, tu ne le lances pas, et tu ne le rends pas. Un assistant d'IA écrit un code plausible, pas un code vérifié : il peut ajouter ce que tu n'as pas demandé, ou se tromper avec assurance. Relire et tester font de toi l'auteur responsable de ce que tu rends. Et la déclaration protège ton intégrité : dans de nombreux établissements, utiliser une IA sans autorisation ni déclaration pour un travail noté est considéré comme une fraude.

À retenirle droit d'abord ; une demande précise, sans données personnelles ; chaque ligne comprise ; testé sur une copie ; aide déclarée.
[4]Entraînement

Bon réflexe ou piège ?

Je colle tout le sujet du TP et je rends la réponse.
tu ne comprends pas ce que tu rends, et c'est souvent une fraude ; demande une aide ciblée, et déclare-la.
Le code tourne et la figure est belle, je le garde.
« ça tourne » n'est pas « c'est juste » ; relis et teste sur un cas connu.
Je demande : “Explique-moi pourquoi mes barres sont décalées.”
une explication t'apprend à corriger seul la prochaine fois.
Je teste le code proposé sur une copie de mes données.
si le code modifie un fichier, l'original est intact.
J'ajoute la déclaration d'aide dans mon compte rendu.
ton enseignante sait ce qui vient de toi, et tu respectes les règles de ton cours.
[5]Quiz

1. Dans la réponse de l'assistant, quelle ligne a modifié le fichier de mesures ?

to_csv écrit le tableau dans le fichier, ici avec des virgules comme séparateur (sortie vérifiée).

2. Tu as 16 ans et tu veux utiliser Claude pour ton TP. Que fais-tu ?

Claude demande d'avoir 18 ans ; ChatGPT, Vibe et Gemini fixent 13 ans, avec un accord parental pour les mineurs chez OpenAI et Mistral AI.

3. Que doit contenir la déclaration d'aide ?

la déclaration permet de savoir précisément ce qui vient de toi.
[6]Kit

🎒 Ton kit — Épisode 19

25 min

Exercice : de la réponse de l'IA au code rendu

  1. Vérifie les règles de ton cours sur l'IA et les conditions d'âge du service. Si tu ne peux pas utiliser d'assistant, prends la réponse fournie ci-dessus.
  2. Sinon, rédige une demande précise pour une fonction qui trace la taille au jour 5 (contexte, but, contraintes, exemple), sans données personnelles.
  3. Relis la réponse ligne par ligne ; surligne tout ce qui écrit, supprime ou envoie quelque chose.
  4. Copie le dossier du TP, teste la fonction dans la copie, corrige-la, ajoute les deux tests.
  5. Rédige la déclaration d'aide de ton TP, puis coche l'auto-diagnostic.

Code à copier : la version relue, corrigée et testée.

Checklist

  • J'ai vérifié les règles de mon cours et les conditions d'âge.
  • J'ai relu chaque ligne et repéré ce qui écrit dans un fichier.
  • J'ai testé sur une copie, sur un cas connu.
  • Ma déclaration d'aide est rédigée.
Vigilancesi tu as moins de l'âge requis par le service, ou sans l'accord nécessaire, tu fais l'exercice avec la réponse fournie par le livre ; jamais avec le compte de quelqu'un d'autre.
[7]Journal

✍️ Journal de bord

Pour ton TP, où tracerais-tu la limite entre « me faire aider » et « faire faire » ? Comment le dirais-tu dans ta déclaration ?

[8]Sources
  1. OpenAI, Age requirements for ChatGPT et conditions d'utilisation pour l'Europe (13 ans minimum ; accord parental entre 13 et 18 ans) (help.openai.com, article 8313401), consulté le 29/10/2026 ; BleepingComputer, OpenAI rolls out age prediction model on ChatGPT (20/01/2026 : expérience restreinte pour les comptes estimés mineurs), consulté le 30/10/2026.
  2. Anthropic, Consumer Terms of Service (en vigueur le 8 octobre 2025 : 18 ans minimum, ou l'âge du consentement dans ton pays s'il est plus élevé), consulté le 30/10/2026.
  3. Mistral AI, Can children use Mistral AI products and services? (mis à jour le 12/08/2026 : 13 ans minimum ; accord d'un parent pour qu'un mineur crée un compte), consulté le 30/10/2026.
  4. Google, What you need to sign in to Gemini Apps (13 ans, ou l'âge applicable dans le pays, avec un compte Google personnel), consulté le 30/10/2026.
  5. Ministère de l'Éducation nationale, Cadre d'usage de l'IA en éducation (juin 2025 : usage autonome au lycée dans un cadre défini ; « Les élèves ne doivent pas avoir à créer de compte personnel ») (copie académique, ac-grenoble.fr), consulté le 30/10/2026.
  6. Aix-Marseille Université, UFR Sciences, Charte d'usage de l'IA générative (approuvée le 10 juillet 2026 : déclaration en tableau outil, usage, passage, précisions ; usage non autorisé pour un travail évalué considéré comme une fraude), consulté le 30/10/2026.
  7. Réponse d'assistant inventée pour le livre, exécutée le 30/10/2026 sur une copie des données, avec Python 3.12.13 et 3.15.0 (journal de test de ce livre).
20
S4 · VENDREDI · Pratiquer · Final

Ton TP, ta boîte à outils et ton certificat

Rendre un TP complet, versionné et relançable, rassembler tes outils, puis célébrer la fin du Pro.

⏱ 25 min · boîte à outils · carrousel · certificat
[1]Scénario
Yanis · Vendredi, 17 h

Yanis envoie le lien de son dépôt. Dedans : le script, les données, requirements.txt, les deux figures, resume.json et un compte rendu d'une page, qui se termine par une ligne « Aide reçue ». Lundi soir, l'enseignante répond : « J'ai cloné votre dépôt, recréé l'environnement, relancé le script : j'obtiens vos figures et vos résultats. Et vous savez expliquer votre écart type. » Awa lève les yeux de son écran : « Le mien, elle ne l'a pas encore relancé. » Yanis sourit. Il y a quatre semaines, il recopiait des lignes qu'il ne comprenait pas.

[2]Outil

Ma boîte à outils d'étudiant

Consigne : termine ton TP avec le script final, vérifie qu'il se relance chez quelqu'un d'autre, puis range tes outils du Pro dans ta boîte à outils.

Le dépôt rendu

Le dossier
tp-croissance/ ├── .gitignore .venv/ et __pycache__/ ├── requirements.txt les versions exactes (épisode 14) ├── croissance.csv les mesures (données inventées) ├── tp_croissance.py le script final, ci-dessous ├── resume.json produit par le script ├── figures/ │ ├── evolution.png │ └── taille_j5.png └── compte_rendu.txt une page, avec la ligne « Aide reçue »

Le script final (code à copier) — tp_croissance.py

Code
"""TP croissance : résume les mesures par éclairage (resume.json) et trace les deux figures du compte rendu."""

import json
from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd

DOSSIER = Path(__file__).parent
FICHIER_MESURES = DOSSIER / "croissance.csv"
FICHIER_RESUME = DOSSIER / "resume.json"
FIGURES = DOSSIER / "figures"
COULEURS = {"bleue": "tab:blue", "rouge": "tab:red", "blanche": "tab:gray"}


def lire_mesures(chemin):
    """Renvoie le tableau des mesures lu dans un CSV séparé par des « ; », à virgule décimale."""
    return pd.read_csv(chemin, sep=";", decimal=",")


def resumer(df):
    """Renvoie le résumé statistique de la taille, une ligne par éclairage."""
    return df.groupby("eclairage", sort=False)["taille_mm"].describe().round(2)


def tracer_evolution(df, image):
    """Trace l'évolution de la taille jour après jour, une courbe par éclairage."""
    plt.figure()
    for eclairage, groupe in df.groupby("eclairage", sort=False):
        plt.plot(groupe["jour"], groupe["taille_mm"], marker="o",
                 color=COULEURS[eclairage], label=f"lumière {eclairage}")
    plt.title("Croissance des plantules selon l'éclairage (J1 à J5)")
    plt.xlabel("Jour de mesure")
    plt.ylabel("Taille (mm)")
    plt.legend()
    plt.savefig(image, dpi=200, bbox_inches="tight")
    plt.close()


def tracer_taille_finale(df, image):
    """Trace la taille au jour 5 par éclairage, en barres partant de zéro."""
    finales = df[df["jour"] == "J5"]
    plt.figure()
    plt.bar(finales["eclairage"], finales["taille_mm"],
            color=[COULEURS[e] for e in finales["eclairage"]])
    plt.title("Taille des plantules au jour 5, par éclairage")
    plt.xlabel("Éclairage")
    plt.ylabel("Taille au jour 5 (mm)")
    plt.ylim(0, 30)
    plt.savefig(image, dpi=200, bbox_inches="tight")
    plt.close()


df = lire_mesures(FICHIER_MESURES)
resume = resumer(df)
assert list(resume["mean"]) == [17.2, 13.6, 18.4]  # cas connu : semaines 2 et 3
with open(FICHIER_RESUME, "w", encoding="utf-8") as fichier:
    json.dump(resume.to_dict(orient="index"), fichier, ensure_ascii=False, indent=2)
FIGURES.mkdir(exist_ok=True)
tracer_evolution(df, FIGURES / "evolution.png")
tracer_taille_finale(df, FIGURES / "taille_j5.png")
print(resume[["count", "mean", "50%", "std"]])
print(f"Écrits : {FICHIER_RESUME.name}, figures/evolution.png, figures/taille_j5.png")

Sortie réelle :

Ce que tu vois
count mean 50% std eclairage bleue 5.0 17.2 17.0 4.28 rouge 5.0 13.6 13.0 2.10 blanche 5.0 18.4 18.5 4.92 Écrits : resume.json, figures/evolution.png, figures/taille_j5.png

to_dict(orient="index") transforme le résumé en dictionnaire {éclairage: {statistique: valeur}}, que json.dump écrit (épisode 13). L'assert garde le cas connu des semaines précédentes : si une mesure du fichier change par erreur, le script s'arrête au lieu de produire un résumé faux.

Le compte rendu (compte_rendu.txt, une page) : la question du TP ; la méthode (mesures, calculs) ; les deux figures et ce qu'elles montrent ; la conclusion, prudente (cinq mesures par éclairage) ; la ligne « Aide reçue » (épisode 19) ; la commande pour tout relancer : python tp_croissance.py, dans un environnement créé avec requirements.txt.

Avant de rendre : clone ton propre dépôt dans un autre dossier, recrée l'environnement, relance le script. Si ça marche chez toi « à neuf », ça marchera chez ton enseignante.

Boîte à outils interactive · Enregistrée dans ce navigateur
[3]Carrousel final

🎨 Carrousel final — Pro

[4]Journal

✍️ Journal de bord — mot de la fin

Relis ta réponse au journal du premier jour. Qu'est-ce qui a changé dans ta façon de rendre un TP ? Quel outil de ta boîte utiliseras-tu dès ton prochain TP ?

✦ ANALYSTE EN HERBE · SEMAINE 4 ✦

Bravo ! Tu as terminé la semaine 4. Tu sais analyser des données avec pandas, tracer des figures honnêtes, versionner ton travail avec Git et te faire aider par une IA en restant l'auteur de ce que tu rends.

[5]Certificat

🎓 Ton certificat

Le certificat s'affiche lorsque les 20 épisodes sont marqués comme terminés.

COLLECTION « CHALLENGES » · APPRENDRE À CODER EN PYTHON

Certificat de réussite

Ce certificat atteste que

—

a terminé les épisodes du Pro — Réussir tes TP Python
et atteint le niveau Analyste en herbe.

Ce que ce parcours couvre : fonctions et docstrings, f-strings, débogage, listes, dictionnaires, tuples et ensembles, lisibilité, bibliothèque standard et documentation, fichiers CSV et JSON, environnements virtuels et paquets, pandas et matplotlib, Git et dépôt distant, usage déclaré d'un assistant d'IA.

[6]Sources
  1. Script final exécuté le 30/10/2026 avec Python 3.12.13 et 3.15.0, pandas 3.1.0 et matplotlib 3.11.2 ; resume.json et figures vérifiés (journal de test de ce livre).
  2. pandas, pandas.DataFrame.to_dict (orient="index" : un dictionnaire {ligne: {colonne: valeur}}), documentation de la version 3.1.0, consulté le 30/10/2026.
Annexe · Kit de rattrapage et glossaire
ARattrapage

Tu démarres le Pro sans avoir suivi le Boost ? Voici, en une ligne chacune, les notions supposées acquises.

  • Algorithme et programme — un calcul que tu sais faire à la main devient une suite d'étapes, puis quelques lignes de Python exécutées de haut en bas (Boost, épisode 1).
  • Variables, types et calculs — = range une valeur ; int, float, str, bool ; + - * / // % ** et leurs priorités ; round (Boost, épisode 1).
  • Conversions — input renvoie toujours du texte ; float(input(...)) pour un nombre ; Python attend un point, pas une virgule (Boost, épisode 1).
  • Lancer un script — un environnement (Thonny, VS Code ou le navigateur), print pour afficher, input pour demander (Boost, épisode 2).
  • Lire une erreur en 3 questions — quelle ligne ? quel type (dernière ligne) ? que dit le message ? (Boost, épisode 2).
  • Décider et répéter — if / elif / else testés dans l'ordre ; for avec range pour un nombre de tours connu ; while tant qu'une condition est vraie ; l'accumulateur initialisé avant la boucle (Boost, épisode 3).
  • Construire pas à pas — une étape, un test, un cas calculé à la main (Boost, épisode 4).
  • Tester comme un utilisateur — saisies hors limites, virgule au lieu du point : le message ValueError se lit et se prévient (Boost, épisode 5).
BGlossaire
Fonction
morceau de code nommé, défini avec def, qui reçoit des valeurs et peut en renvoyer une.
Paramètre
nom, dans la définition d'une fonction, qui reçoit une valeur à l'appel.
Argument
valeur donnée à une fonction au moment de l'appel.
Valeur renvoyée
résultat transmis par return à celui qui appelle ; None s'il n'y a pas de return.
Portée
partie du programme où une variable existe ; une variable créée dans une fonction est locale à cet appel.
Docstring
texte entre triples guillemets, sous le def ou en tête de fichier, qui dit ce que fait le code.
Chaîne de caractères (str)
un texte, suite de caractères numérotés à partir de 0, qu'on ne peut pas modifier sur place.
Tranche
morceau d'une chaîne ou d'une liste, noté [début:fin], la fin étant exclue.
f-string
texte précédé de f, où ce qui est entre accolades est remplacé par sa valeur, éventuellement mise en forme (:.2f).
Bug silencieux
erreur qui ne provoque aucun message mais donne un résultat faux.
Débogueur
outil qui exécute un programme pas à pas et montre la valeur de ses variables.
Point d'arrêt
ligne où le débogueur met le programme en pause.
Liste
suite ordonnée de valeurs, entre crochets, qu'on peut modifier (append, sort).
Indice
numéro d'un élément dans une liste ou d'un caractère dans une chaîne ; le premier est 0, le dernier -1.
Dictionnaire
ensemble de paires clé-valeur, entre accolades, pour retrouver une valeur par son nom.
Clé
nom qui donne accès à une valeur dans un dictionnaire ; elle est unique.
Tuple
suite ordonnée de valeurs, entre parenthèses, qu'on ne modifie pas.
Ensemble (set)
collection de valeurs distinctes, sans ordre ni doublon.
Module
fichier de code Python qu'on charge avec import.
Bibliothèque standard
l'ensemble des modules fournis avec Python (math, statistics, csv, json, pathlib…).
Chemin
adresse d'un fichier ou d'un dossier, manipulée avec pathlib.Path.
Encodage
façon de traduire les caractères en octets dans un fichier ; on choisit UTF-8.
CSV
fichier texte de tableau, une ligne par enregistrement, des valeurs séparées par un séparateur (, ou ;).
JSON
format texte de données structurées (dictionnaires, listes, nombres, textes), lisible par de nombreux langages.
Paquet
bibliothèque qu'on installe depuis PyPI avec pip (pandas, matplotlib).
Environnement virtuel
dossier qui contient un Python et les paquets propres à un projet.
DataFrame
tableau de pandas, avec des lignes indexées et des colonnes nommées et typées.
Dépôt
dossier dont Git garde l'historique.
Commit
enregistrement de l'état des fichiers dans l'historique d'un dépôt, avec un message.
Dépôt distant
copie d'un dépôt hébergée ailleurs (sur un service en ligne), avec laquelle on échange par push et clone.