Exercice 1 : QCM
Pour chaque question, une seule réponse est correcte.
1. Quelle instruction Python permet de vérifier une condition et d’interrompre le programme si elle est fausse ?
- A.
try condition - B.
raise condition - C.
assert condition - D.
if not condition: exit()
Correction publiée après la séance.
2. Pourquoi la condition while lst[i] < 100 and i < len(lst) est-elle dangereuse ?
- A.
len(lst)recalcule la longueur à chaque itération - B. La condition devrait utiliser
orau lieu deand - C. Il manque une instruction
break - D. Python accède à
lst[i]avant de vérifier queiest un indice valide
Correction publiée après la séance.
3. Que vaut 0.1 + 0.2 == 0.3 en Python ?
- A.
True - B.
False - C.
None - D. Une erreur est levée
Correction publiée après la séance.
4. Quel est le résultat de ce code ?
x = [1, 2, 3]
y = x
y.append(4)
print(len(x))
- A. 3
- B. 4
- C. Une erreur
AttributeError - D. Une erreur
TypeError
Correction publiée après la séance.
Exercice 2 : identifier les erreurs
Pour chaque extrait de code, identifiez le type d’erreur que Python va lever et expliquez pourquoi.
a)
def saluer(nom)
print(f"Bonjour {nom}")
Indice
Comparer cette ligne def à celles des fonctions habituelles : que manque-t-il à sa fin ?
b)
notes = [15, 12, 18]
print(notes[3])
Indice
La liste contient trois éléments : quels sont leurs indices ?
c)
age = input("Votre âge : ")
annee_naissance = 2026 - age
Indice
Quel est le type de la valeur renvoyée par input ? Peut-on soustraire une chaîne d’un entier ?
d)
def diviser(a, b):
return a / b
print(diviser(10, 0))
Indice
Que vaut le second nombre de la division a / b lors de cet appel ?
e)
dico = {"a": 1, "b": 2}
print(dico["c"])
Indice
Quelles sont les clés du dictionnaire ?
Correction publiée après la séance.
Exercice 3 : tracer l’exécution avec print (exercice guidé)
La fonction suivante est censée renvoyer l’indice du maximum d’une liste, et l’on veut vérifier son comportement sur des cas limites.
def indice_max(L):
i_max = 0
for i in range(len(L)):
if L[i] > L[i_max]:
i_max = i
return i_max
a) Testez indice_max([3, 7, 2, 9, 1]). Quel résultat obtenez-vous ? Est-il correct ?
Indice
Repérer à la main la position du plus grand élément, en comptant les indices à partir de 0, et la comparer au résultat.
b) Testez indice_max([5, 5, 5]). Quel résultat obtenez-vous ? Est-ce le comportement attendu ?
Indice
Avec des éléments tous égaux, la comparaison L[i] > L[i_max] est-elle vraie une seule fois ? Quel indice reste alors dans i_max ?
c) Ajoutez des print dans la boucle pour tracer les valeurs de i, L[i], i_max et L[i_max] à chaque itération. Exécutez sur [3, 7, 2, 9, 1] et copiez la trace.
Indice
Placer un print au début du corps de la boucle, avec une f-string qui affiche les quatre valeurs.
Code à copier puis compléter
def indice_max(L):
i_max = 0
for i in range(len(L)):
print(f"i = {i}, L[i] = {...}, i_max = {i_max}, L[i_max] = {...}")
if L[i] > L[i_max]:
i_max = i
return i_max
indice_max([3, 7, 2, 9, 1])
d) Testez maintenant indice_max([9, 1, 9, 1]). Quel indice est renvoyé ? Si l’on souhaite renvoyer le dernier indice du maximum (et non le premier), quelle modification faut-il apporter ?
Indice
Lorsque L[i] est égal au maximum déjà trouvé, i_max change-t-il ? Quelle comparaison le ferait changer ?
Correction publiée après la séance.
Exercice 4 : les pièges des flottants
a) Exécutez les expressions suivantes en Python et notez les résultats :
0.1 + 0.2
0.1 + 0.2 == 0.3
1.0 + 1e-16 == 1.0
Expliquez chaque résultat.
Indice
0,1 et 0,2 n’ont pas d’écriture binaire finie : ils sont stockés arrondis. Quant à 1e-16, il est trop petit devant 1 pour modifier le flottant 1.0, dont la précision est d’environ 16 chiffres significatifs.
b) La fonction suivante est censée vérifier si un triangle est rectangle en utilisant le théorème de Pythagore. Pourquoi peut-elle échouer avec certaines valeurs ?
def est_rectangle(a, b, c):
"""Vérifie si un triangle de côtés a, b, c est rectangle."""
cotes = sorted([a, b, c])
return cotes[0]**2 + cotes[1]**2 == cotes[2]**2
Indice
Avec des côtés à virgule, les carrés sont-ils calculés exactement ? Que devient alors le test == ?
c) Réécrivez la fonction en utilisant une comparaison avec tolérance. On utilisera abs(x - y) < epsilon avec epsilon = 1e-9.
Indice
Remplacer l’égalité par le test d’un écart, en valeur absolue, plus petit que epsilon.
Code à copier puis compléter
def est_rectangle(a, b, c, epsilon=1e-9):
cotes = sorted([a, b, c])
return abs(cotes[0]**2 + cotes[1]**2 - ...) < ...
d) Testez les deux versions avec le triangle de côtés $0.5$, $1.2$ et $1.3$. Que constatez-vous ?
Indice
Appeler chaque version avec les côtés 0.5, 1.2 et 1.3, puis afficher 0.5**2 + 1.2**2 et 1.3**2 pour comparer les deux nombres.
Correction publiée après la séance.
Exercice 5 : écrire des assertions et des tests
a) Écrire des assertions de précondition pour la fonction moyenne(L) : la liste ne doit pas être vide et tous ses éléments doivent être des nombres.
Indice
Une première assertion porte sur len(L). Pour la seconde, parcourir la liste et vérifier le type de chaque élément avec isinstance(x, (int, float)).
Code à copier puis compléter
def moyenne(L):
assert len(L) > 0, "La liste ne doit pas être vide"
for x in L:
assert isinstance(x, (int, float)), ...
return sum(L) / ...
b) Compléter les docstrings de la fonction suivante avec des doctests couvrant les cas normaux et les cas limites :
def est_palindrome(s):
"""
Renvoie True si la chaîne s est un palindrome, False sinon.
>>> # Écrire les doctests ici
"""
return s == s[::-1]
Indice
Un doctest s’écrit >>> est_palindrome("radar"), suivi à la ligne suivante du résultat attendu, True. Prévoir un palindrome, un mot qui n’en est pas un, la chaîne vide et une chaîne d’un seul caractère.
c) Pour la fonction tri_insertion(L), proposer au moins quatre jeux de tests pertinents (liste quelconque, liste vide, liste déjà triée, liste avec doublons) et justifier le choix de chacun.
Indice
Pour chaque jeu de tests, dire quelle erreur de programmation il pourrait révéler : une boucle qui ne s’exécute pas, une liste déjà rangée, des éléments égaux mal placés.
Correction publiée après la séance.
Exercice 6 : chasse aux bugs
Chacun des programmes suivants contient un bug relevant d’une cause classique. Identifiez l’erreur, nommez sa cause et proposez une correction.
a) Indentation incorrecte :
def compter_voyelles(mot):
voyelles = "aeiouy"
compteur = 0
for i in range(len(mot)):
if mot[i] in voyelles:
compteur += 1
return compteur
Indice
Regarder l’indentation du return : à quel bloc appartient-il, et combien de tours de boucle s’exécutent avant lui ?
b) Effet de bord :
def inverser_liste(L):
resultat = L
resultat.reverse()
return resultat
ma_liste = [1, 2, 3]
inversee = inverser_liste(ma_liste)
print(ma_liste)
Indice
resultat = L ne crée pas de copie : les deux noms désignent la même liste. Que fait alors reverse sur ma_liste ?
c) Choix d’inégalité :
def somme_entiers(n):
s = 0
i = 1
while i < n:
s += i
i += 1
return s
print(somme_entiers(5)) # Attendu : 15, obtenu : ?
Indice
Quelles valeurs de i sont ajoutées tant que i < n ? La valeur 5 est-elle prise ?
d) Conditionnelle non exhaustive :
def mention(moyenne):
if moyenne >= 16:
return "Très bien"
elif moyenne >= 14:
return "Bien"
elif moyenne >= 12:
return "Assez bien"
print(mention(10)) # Que se passe-t-il ?
Indice
Pour une moyenne de 10, aucune condition n’est vraie : que renvoie une fonction qui atteint sa fin sans rencontrer de return ?
e) Mauvais nommage :
list = [4, 7, 2, 9]
somme = sum(list)
list = list + [5] # Que se passe-t-il ici ?
Indice
list est aussi le nom de la fonction prédéfinie qui convertit en liste : que devient-elle après l’affectation de la première ligne ?
f) Comparaison de flottants :
x = 0.1 + 0.1 + 0.1
if x == 0.3:
print("Égal")
else:
print("Différent") # Quel message s'affiche ?
Indice
Comme à l’exercice 4, 0,1 n’a pas d’écriture binaire exacte : la somme de trois 0,1 vaut-elle exactement 0,3 ?
Correction publiée après la séance.
Exercice 7 : gestion des exceptions
a) Écrire une fonction saisie_entier() qui demande à l’utilisateur de saisir un entier et redemande tant que la saisie n’est pas valide. Utiliser try/except.
Indice
Une boucle while True recommence tant qu’il le faut. Dans un bloc try, renvoyer int(...) de la saisie : si la conversion échoue, le bloc except ValueError affiche un message et la boucle recommence.
Code à copier puis compléter
def saisie_entier():
while True:
try:
return int(input(...))
except ValueError:
print(...)
b) Écrire une fonction lire_fichier(chemin) qui renvoie le contenu d’un fichier sous forme de chaîne, ou "Fichier introuvable" si le fichier n’existe pas.
Indice
Ouvrir et lire le fichier dans un bloc try ; l’exception levée quand le fichier n’existe pas est FileNotFoundError.
Code à copier puis compléter
def lire_fichier(chemin):
try:
with open(chemin, "r") as f:
return f.read()
except ...:
return ...
c) Définir une exception personnalisée NoteInvalideError et une fonction ajouter_note(notes, n) qui lève cette exception si n n’est pas entre 0 et 20.
Indice
Une exception personnalisée est une classe qui hérite de Exception : class NoteInvalideError(Exception):, suivie de pass. La fonction vérifie la note, lève l’exception avec raise NoteInvalideError(...) si elle est hors de l’intervalle, et sinon l’ajoute à la liste.
Correction publiée après la séance.
Exercice 8 : synthèse – débogage complet d’un programme
Le programme suivant est censé lire une liste de notes séparées par des virgules, calculer la moyenne et afficher le résultat avec une mention. Il contient deux bugs et deux situations d’erreur non gérées. Les trouver, les corriger et ajouter une gestion d’erreur appropriée.
def calculer_moyenne(chaine):
notes = chaine.split(",")
somme = 0
for note in notes:
somme += note
moyenne = somme / len(notes)
if moyenne >= 10:
mention = "admis"
elif moyenne >= 8:
mention = "rattrapage"
return f"Moyenne : {moyenne}/20 ({mention})"
resultat = calculer_moyenne("12,15,8,14,9")
print(resultat)
Indice
Exécuter le programme et lire le message d’erreur : de quel type est chaque note après split ? Chercher ensuite les situations non prévues : une moyenne inférieure à 8, qui laisse mention sans valeur, puis une chaîne vide ou qui contient autre chose que des nombres.
Correction publiée après la séance.