notes = {
"Alice": 14,
"Bob": 12,
"Charlie": 17,
"Diana": 9,
"Eve": 15,
"Frank": 11,
"Grace": 8,
"Hugo": 13,
"Iris": 18,
"Julien": 10,
}19 TP récapitulatif — Analyse des notes d’une classe
Ce Travail Pratique mobilise toutes les notions du niveau Basique : variables, types, opérateurs, conditions, boucles, listes, tuples, dictionnaires, ensembles, fonctions natives.
19.1 Contexte
Un professeur vous demande de l’aider à analyser les notes de sa classe. Voici les données :
Vous allez écrire progressivement un programme qui répond aux demandes ci-dessous. Chaque partie est indépendante — si vous bloquez sur une, passez à la suivante.
- Lisez d’abord toutes les questions pour avoir une vue d’ensemble.
- Commencez par la Partie 1 (la plus simple) pour vous mettre en confiance.
- Testez après chaque question : n’écrivez pas 30 lignes sans vérifier.
- Réutilisez les variables des questions précédentes quand c’est pertinent.
- N’hésitez pas à revenir dans les chapitres précédents pour relire une méthode.
Partie 1 — Statistiques générales
Questions
- Calculer et afficher la note moyenne de la classe (arrondie à 2 décimales).
- Afficher la note la plus haute et la note la plus basse.
- Afficher le nom de l’élève ayant obtenu la meilleure note et celui ayant la plus basse.
- Calculer et afficher l’écart entre la meilleure et la moins bonne note.
notes = {
"Alice": 14,
"Bob": 12,
"Charlie": 17,
"Diana": 9,
"Eve": 15,
"Frank": 11,
"Grace": 8,
"Hugo": 13,
"Iris": 18,
"Julien": 10,
}
# Q1 : moyenne
moyenne = sum(notes.values()) / len(notes)
print(f"Moyenne : {round(moyenne, 2)}")
# Q2 : max et min
note_max = max(notes.values())
note_min = min(notes.values())
print(f"Note max : {note_max}")
print(f"Note min : {note_min}")
# Q3 : noms associés
# On parcourt les items pour retrouver qui a quelle note
for prenom, note in notes.items():
if note == note_max:
print(f"Meilleur : {prenom}")
if note == note_min:
print(f"Moins bon : {prenom}")
# Q4 : écart
print(f"Écart : {note_max - note_min}")Moyenne : 12.7
Note max : 18
Note min : 8
Moins bon : Grace
Meilleur : Iris
Écart : 10
Alternative Q3 avec max(..., key=...)
Une version plus Pythonique utilise max sur les clés avec key :
# Astuce : on prend le MAX des clés selon leur valeur associée
meilleur = max(notes, key=notes.get)
moins_bon = min(notes, key=notes.get)
print(f"Meilleur : {meilleur}")
print(f"Moins bon : {moins_bon}")Meilleur : Iris
Moins bon : Grace
Avantage : ne renvoie qu’un seul élève, même si plusieurs ont la même note (le premier trouvé). La version avec boucle renvoie tous les ex æquo.
Partie 2 — Analyse par mentions
On définit les mentions suivantes :
| Note | Mention |
|---|---|
| < 10 | Insuffisant |
| 10 ≤ note < 12 | Passable |
| 12 ≤ note < 14 | Assez bien |
| 14 ≤ note < 16 | Bien |
| ≥ 16 | Très bien |
Questions
- Parcourir le dictionnaire et afficher pour chaque élève une ligne de la forme :
"Alice a obtenu 14 (Bien)". - Compter combien d’élèves ont chaque mention.
- Afficher le nombre d’élèves ayant la moyenne (note ≥ 10) et le pourcentage de réussite.
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# On factorise le calcul de la mention dans une fonction
def mention(note):
if note < 10:
return "Insuffisant"
elif note < 12:
return "Passable"
elif note < 14:
return "Assez bien"
elif note < 16:
return "Bien"
else:
return "Très bien"
# Q1 : afficher chaque élève avec sa mention
for prenom, note in notes.items():
print(f"{prenom} a obtenu {note} ({mention(note)})")
# Q2 : compter les mentions
compteur = {}
for note in notes.values():
m = mention(note)
compteur[m] = compteur.get(m, 0) + 1
print("\nRépartition des mentions :")
for m, n in compteur.items():
print(f" {m} : {n}")
# Q3 : pourcentage de réussite
admis = sum(1 for n in notes.values() if n >= 10)
total = len(notes)
print(f"\nAdmis : {admis} / {total}")
print(f"Taux de réussite : {admis / total * 100:.1f}%")Alice a obtenu 14 (Bien)
Bob a obtenu 12 (Assez bien)
Charlie a obtenu 17 (Très bien)
Diana a obtenu 9 (Insuffisant)
Eve a obtenu 15 (Bien)
Frank a obtenu 11 (Passable)
Grace a obtenu 8 (Insuffisant)
Hugo a obtenu 13 (Assez bien)
Iris a obtenu 18 (Très bien)
Julien a obtenu 10 (Passable)
Répartition des mentions :
Bien : 2
Assez bien : 2
Très bien : 2
Insuffisant : 2
Passable : 2
Admis : 8 / 10
Taux de réussite : 80.0%
Notions mobilisées
dict.get(clé, 0)pour initialiser un compteur à 0 si la clé n’existe pas encore.sum(1 for n in ... if ...)pour compter les éléments qui vérifient une condition (expression génératrice, vue en Partie 3 — à ce stade, on peut aussi utiliser unforexplicite avec un compteur).f"{x:.1f}"pour formater un float à 1 décimale (f-strings, vues en Partie 2).
Partie 3 — Doublons et ensembles
Questions
- Construire la liste des notes uniques (sans doublons) en utilisant un
set. Combien de notes distinctes la classe a-t-elle obtenues ? - Utiliser un
setpour trouver les notes qui n’ont été obtenues qu’une seule fois.
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# Q1 : notes distinctes
notes_distinctes = set(notes.values())
print(f"Nombre de notes distinctes : {len(notes_distinctes)}")
print(f"Notes distinctes : {sorted(notes_distinctes)}")
# Q2 : notes obtenues une seule fois
# On compte l'occurrence de chaque note, puis on filtre
toutes_notes = list(notes.values())
uniques = set()
for note in notes_distinctes:
if toutes_notes.count(note) == 1:
uniques.add(note)
print(f"Notes obtenues une seule fois : {sorted(uniques)}")Nombre de notes distinctes : 10
Notes distinctes : [8, 9, 10, 11, 12, 13, 14, 15, 17, 18]
Notes obtenues une seule fois : [8, 9, 10, 11, 12, 13, 14, 15, 17, 18]
Version avec Counter (bibliothèque standard)
Python propose un outil dédié pour compter les occurrences :
from collections import Counter
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
compteur = Counter(notes.values())
print(compteur)
uniques = [n for n, c in compteur.items() if c == 1]
print(f"Notes uniques : {sorted(uniques)}")Counter({14: 1, 12: 1, 17: 1, 9: 1, 15: 1, 11: 1, 8: 1, 13: 1, 18: 1, 10: 1})
Notes uniques : [8, 9, 10, 11, 12, 13, 14, 15, 17, 18]
On voit les modules en détail au niveau Opérationnel (Partie 2).
Partie 4 — Tirage aléatoire (bonus)
Question
- Utiliser le module
randompour tirer au hasard un élève qui passera au tableau. Afficher son nom et sa note.
import random
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# random.choice prend un élément au hasard dans une séquence
prenom_au_hasard = random.choice(list(notes.keys()))
print(f"Au tableau : {prenom_au_hasard} (note : {notes[prenom_au_hasard]})")Au tableau : Diana (note : 9)
Variante : tirer plusieurs élèves sans remise
import random
# random.sample tire k éléments DIFFÉRENTS (sans remise)
equipe = random.sample(list(notes.keys()), k=3)
print(f"Équipe pour l'oral : {equipe}")Équipe pour l'oral : ['Hugo', 'Eve', 'Charlie']
Notions mobilisées
random.choice(seq)— tire un élément au hasard dans une séquence.random.sample(seq, k)— tirekéléments distincts.- Conversion
list(notes.keys())carrandom.choicea besoin d’une séquence indexable.
Les modules sont vus plus en détail en Partie 2.
Partie 5 — Interaction utilisateur
Questions
- Demander un prénom à l’utilisateur et afficher sa note et sa mention. Gérer le cas où le prénom n’existe pas (message d’erreur approprié).
- Demander une note seuil (entier) et afficher la liste des élèves ayant une note ≥ au seuil.
import random
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
def mention(note):
if note < 10:
return "Insuffisant"
elif note < 12:
return "Passable"
elif note < 14:
return "Assez bien"
elif note < 16:
return "Bien"
else:
return "Très bien"
# Q1 : recherche par prénom
prenom_saisi = input("Quel prénom chercher ? ").strip()
if prenom_saisi in notes:
note = notes[prenom_saisi]
print(f"{prenom_saisi} a obtenu {note} ({mention(note)})")
else:
print(f"Prénom '{prenom_saisi}' non trouvé dans la classe.")
# Q2 : filtrer par seuil
seuil = int(input("Note seuil : "))
print(f"\nÉlèves ayant une note ≥ {seuil} :")
for prenom, note in notes.items():
if note >= seuil:
print(f" - {prenom} ({note})")Démonstration (sans input) avec des valeurs simulées
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
def mention(note):
if note < 10: return "Insuffisant"
elif note < 12: return "Passable"
elif note < 14: return "Assez bien"
elif note < 16: return "Bien"
else: return "Très bien"
# Simulation Q1
for prenom_saisi in ["Alice", "Xavier"]:
if prenom_saisi in notes:
note = notes[prenom_saisi]
print(f"{prenom_saisi} a obtenu {note} ({mention(note)})")
else:
print(f"Prénom '{prenom_saisi}' non trouvé.")
# Simulation Q2
seuil = 14
print(f"\nÉlèves ayant une note ≥ {seuil} :")
for prenom, note in notes.items():
if note >= seuil:
print(f" - {prenom} ({note})")Alice a obtenu 14 (Bien)
Prénom 'Xavier' non trouvé.
Élèves ayant une note ≥ 14 :
- Alice (14)
- Charlie (17)
- Eve (15)
- Iris (18)
Points clés
prenom in notes: test d’appartenance sur les clés du dict..strip()sur la saisie utilisateur pour retirer les espaces parasites.int(input(...))pour convertir la saisie en entier.
Partie 6 — Classement et présentation
Questions
Afficher le classement complet de la classe (du meilleur au moins bon) avec
enumeratepour numéroter :1. Iris : 18 2. Charlie : 17 3. Eve : 15 ...Indice : trier les items du dictionnaire par note décroissante avec :
sorted(notes.items(), key=lambda t: t[1], reverse=True)(La syntaxe
lambdasera vue en Partie 3 — à ce stade, accepter la formule telle quelle ou passer par une liste de tuples classique.)Construire la chaîne
"Iris, Charlie, Eve, ..."(noms séparés par virgule) représentant le classement. Indice : utilisez.join().Pour chaque élève, construire un « badge » au format
[ALICE-14]en mettant le prénom en majuscules (utilisez.upper()). Afficher tous les badges sur une seule ligne.
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# Q1 : classement numéroté
classement = sorted(notes.items(), key=lambda t: t[1], reverse=True)
print("=== Classement ===")
for rang, (prenom, note) in enumerate(classement, start=1):
print(f"{rang}. {prenom} : {note}")
# Q2 : chaîne des noms, séparés par virgule
noms_classement = [prenom for prenom, note in classement]
chaine_noms = ", ".join(noms_classement)
print(f"\nOrdre : {chaine_noms}")
# Q3 : badges
badges = []
for prenom, note in notes.items():
badge = f"[{prenom.upper()}-{note}]"
badges.append(badge)
print("\nBadges :", " ".join(badges))=== Classement ===
1. Iris : 18
2. Charlie : 17
3. Eve : 15
4. Alice : 14
5. Hugo : 13
6. Bob : 12
7. Frank : 11
8. Julien : 10
9. Diana : 9
10. Grace : 8
Ordre : Iris, Charlie, Eve, Alice, Hugo, Bob, Frank, Julien, Diana, Grace
Badges : [ALICE-14] [BOB-12] [CHARLIE-17] [DIANA-9] [EVE-15] [FRANK-11] [GRACE-8] [HUGO-13] [IRIS-18] [JULIEN-10]
Version sans lambda (Partie 1)
Puisqu’on n’a pas encore vu les lambdas, voici une alternative :
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# Construire une liste de tuples (note, prenom) puis trier naturellement
# Astuce : en inversant l'ordre (note, prenom), le tri se fait sur la note
paires = []
for prenom, note in notes.items():
paires.append((note, prenom))
# Tri décroissant par note
paires.sort(reverse=True)
print("=== Classement ===")
for rang, (note, prenom) in enumerate(paires, start=1):
print(f"{rang}. {prenom} : {note}")=== Classement ===
1. Iris : 18
2. Charlie : 17
3. Eve : 15
4. Alice : 14
5. Hugo : 13
6. Bob : 12
7. Frank : 11
8. Julien : 10
9. Diana : 9
10. Grace : 8
Notions mobilisées
sorted(dict.items(), key=..., reverse=True)— trier un dict par valeur.enumerate(..., start=1)— numérotation qui démarre à 1.- Déballage
(prenom, note)dans la boucle. .join(liste)pour concaténer des chaînes avec un séparateur.- Chaînage de méthodes (
prenom.upper()). - f-strings pour le formatage propre.
🏆 Bonus — Pour aller plus loin
Une fois les 6 parties maîtrisées, essayez ces défis supplémentaires :
Histogramme ASCII : affichez un diagramme en barres des notes, une ligne par élève, en utilisant
*(une étoile par point de note). Exemple :Alice | ************** (14) Charlie | ***************** (17)Recherche d’ex æquo : affichez les paires d’élèves qui ont exactement la même note.
Note la plus fréquente : quelle est la note qui revient le plus souvent dans la classe ? (Si plusieurs, affichez toutes.)
Histogramme
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# Largeur max des prénoms pour aligner
largeur = max(len(p) for p in notes)
for prenom, note in notes.items():
barres = "*" * note
print(f"{prenom:<{largeur}} | {barres} ({note})")Alice | ************** (14)
Bob | ************ (12)
Charlie | ***************** (17)
Diana | ********* (9)
Eve | *************** (15)
Frank | *********** (11)
Grace | ******** (8)
Hugo | ************* (13)
Iris | ****************** (18)
Julien | ********** (10)
Ex æquo
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
# Inverser : note → liste des prénoms
par_note = {}
for prenom, note in notes.items():
if note not in par_note:
par_note[note] = []
par_note[note].append(prenom)
# Afficher les notes avec plusieurs élèves
print("Ex æquo :")
for note, prenoms in par_note.items():
if len(prenoms) > 1:
print(f" Note {note} : {', '.join(prenoms)}")Ex æquo :
Sur notre jeu de données, il n’y a pas d’ex æquo car toutes les notes sont distinctes. Testez en modifiant une note pour créer un doublon.
Note la plus fréquente
from collections import Counter
notes = {
"Alice": 14, "Bob": 12, "Charlie": 17, "Diana": 9, "Eve": 15,
"Frank": 11, "Grace": 8, "Hugo": 13, "Iris": 18, "Julien": 10,
}
compteur = Counter(notes.values())
freq_max = max(compteur.values())
plus_frequentes = [n for n, c in compteur.items() if c == freq_max]
print(f"Note(s) la/les plus fréquente(s) : {plus_frequentes} ({freq_max} occurrences)")Note(s) la/les plus fréquente(s) : [14, 12, 17, 9, 15, 11, 8, 13, 18, 10] (1 occurrences)
✅ Validation du niveau Basique
Si vous avez réussi à résoudre les 6 parties (même avec l’aide des solutions pour quelques-unes), vous maîtrisez l’essentiel du niveau Basique TOSA :
- ✅ Variables, types et conversions
- ✅ Opérateurs arithmétiques, logiques et de comparaison
- ✅ Chaînes de caractères et leurs méthodes
- ✅ Conditions
if/elif/else - ✅ Les 4 structures : listes, tuples, dictionnaires, ensembles
- ✅ Boucles
for/while,break/continue - ✅ Fonctions natives :
min,max,sum,len,sorted,enumerate,zip…
Score TOSA estimé : 351-550 (niveau Basique).
Prêt(e) pour la Partie 2 — Niveau Opérationnel ? Vous y découvrirez les fonctions (vos propres fonctions !), les f-strings, la mutabilité et bien plus.
← Chapitre précédent : Fonctions natives • Partie 2 — Niveau Opérationnel →