Chapitre 0 - Partie 2 : Mise au point des programmes et gestion des bugs
1. Les types de bugs
Section intitulée « 1. Les types de bugs »1.1 Erreurs de syntaxe
Section intitulée « 1.1 Erreurs de syntaxe »Détectées avant l'exécution par l'interpréteur Python. Le programme ne démarre pas.
# Parenthèse manquanteprint("bonjour"# SyntaxError: unexpected EOF while parsing
# Indentation incorrectedef f():print("test")# IndentationError: expected an indented block1.2 Erreurs d'exécution (exceptions)
Section intitulée « 1.2 Erreurs d'exécution (exceptions) »Détectées pendant l'exécution. Le programme s'arrête brutalement.
# Division par zéroprint(10 / 0)# ZeroDivisionError
# Index hors limitestab = [1, 2, 3]print(tab[5])# IndexError: list index out of range
# Type incompatibleprint("age : " + 17)# TypeError: can only concatenate str to str1.3 Erreurs logiques (sémantiques)
Section intitulée « 1.3 Erreurs logiques (sémantiques) »Les plus difficiles à détecter : le programme s'exécute sans erreur mais produit un résultat faux.
# Bug : calcul de la moyennedef moyenne(notes): return sum(notes) / len(notes) + 1 # le + 1 est une erreur2. Causes typiques de bugs
Section intitulée « 2. Causes typiques de bugs »2.1 Problèmes liés au typage
Section intitulée « 2.1 Problèmes liés au typage »# Concaténation au lieu d'additionage = input("Âge : ") # renvoie une chaîneprint(age + 1) # TypeError !# Correction : int(input("Âge : "))
# Confusion entier / flottantprint(7 / 2) # 3.5 (division réelle)print(7 // 2) # 3 (division entière)2.2 Effets de bord non désirés
Section intitulée « 2.2 Effets de bord non désirés »Un effet de bord se produit quand une fonction modifie quelque chose en dehors d'elle (variable globale, argument mutable).
# Bug classique : modification d'une liste passée en argumentdef ajouter_element(liste, element): liste.append(element) # modifie la liste originale ! return liste
ma_liste = [1, 2, 3]nouvelle = ajouter_element(ma_liste, 4)print(ma_liste) # [1, 2, 3, 4] - modifiée involontairement !# Correction : travailler sur une copiedef ajouter_element(liste, element): copie = liste.copy() copie.append(element) return copie# Bug classique : argument par défaut mutabledef ajouter(element, liste=[]): # DANGER ! liste.append(element) return liste
print(ajouter(1)) # [1]print(ajouter(2)) # [1, 2] - surprise !# Correction : utiliser None comme valeur par défautdef ajouter(element, liste=None): if liste is None: liste = [] liste.append(element) return liste2.3 Débordements dans les tableaux
Section intitulée « 2.3 Débordements dans les tableaux »tab = [10, 20, 30]
# Bug : index hors limitesfor i in range(len(tab) + 1): # range(4) → 0, 1, 2, 3 print(tab[i]) # IndexError quand i = 3
# Correctionfor i in range(len(tab)): # range(3) → 0, 1, 2 print(tab[i])2.4 Instruction conditionnelle non exhaustive
Section intitulée « 2.4 Instruction conditionnelle non exhaustive »# Bug : cas non traitédef categorie(age): if age < 12: return "enfant" elif age < 18: return "adolescent" # Que se passe-t-il si age >= 18 ? → renvoie None
# Correctiondef categorie(age): if age < 12: return "enfant" elif age < 18: return "adolescent" else: return "adulte"2.5 Choix des inégalités (erreur « off-by-one »)
Section intitulée « 2.5 Choix des inégalités (erreur « off-by-one ») »# Bug : < au lieu de <=def est_dans_intervalle(x, a, b): return a < x < b # exclut a et b
# Si on veut inclure les bornes :def est_dans_intervalle(x, a, b): return a <= x <= b# Bug : boucle qui itère une fois de trop ou de moinsfor i in range(1, 10): # 1, 2, ..., 9 (pas 10 !)for i in range(1, 11): # 1, 2, ..., 102.6 Comparaisons entre flottants
Section intitulée « 2.6 Comparaisons entre flottants »# Bug : comparaison directe de flottantsprint(0.1 + 0.2 == 0.3) # False !print(0.1 + 0.2) # 0.30000000000000004
# Correction : comparer avec une tolérancedef presque_egal(a, b, epsilon=1e-9): return abs(a - b) < epsilon
print(presque_egal(0.1 + 0.2, 0.3)) # True2.7 Mauvais nommage des variables
Section intitulée « 2.7 Mauvais nommage des variables »# Bug : confusion entre variables aux noms procheslongueur = 10largeur = 5aire = longueur * longueur # devrait être longueur * largeur
# Bug : variable locale masquant une variable de portée supérieuretotal = 100def ajouter(n): total = 0 # crée une variable locale, ne modifie pas la globale total += n return total3. Techniques de débogage
Section intitulée « 3. Techniques de débogage »3.1 Affichage avec print
Section intitulée « 3.1 Affichage avec print »La méthode la plus simple : insérer des print() pour observer les valeurs des variables.
def recherche(tab, val): for i in range(len(tab)): print(f" i={i}, tab[i]={tab[i]}, val={val}") # debug if tab[i] == val: return i return -13.2 Assertions
Section intitulée « 3.2 Assertions »Les assertions vérifient des conditions qui doivent être vraies. Si la condition est fausse, le programme s'arrête avec un message explicite.
def moyenne(notes): assert len(notes) > 0, "La liste de notes ne doit pas être vide" assert all(0 <= n <= 20 for n in notes), "Notes entre 0 et 20" return sum(notes) / len(notes)3.3 Documentation et spécification
Section intitulée « 3.3 Documentation et spécification »def recherche_dicho(tab, val): """Recherche val dans tab (trié) par dichotomie.
Args: tab: liste triée par ordre croissant val: valeur à rechercher
Returns: L'indice de val si trouvé, -1 sinon.
Raises: AssertionError: si tab n'est pas trié. """ assert all(tab[i] <= tab[i+1] for i in range(len(tab)-1)), "tab doit être trié" # ...3.4 Jeux de tests
Section intitulée « 3.4 Jeux de tests »Tester systématiquement avec des cas variés :
def est_premier(n): if n < 2: return False for i in range(2, int(n ** 0.5) + 1): if n % 2 == 0: return False return True
# Jeu de testsassert est_premier(2) == Trueassert est_premier(3) == Trueassert est_premier(4) == Falseassert est_premier(17) == Trueassert est_premier(1) == Falseassert est_premier(0) == Falseassert est_premier(-5) == False# Bug détecté ! est_premier(9) renvoie True au lieu de False# Cause : n % 2 au lieu de n % i dans la boucle3.5 Le débogueur
Section intitulée « 3.5 Le débogueur »Un débogueur (Thonny, VS Code, etc.) permet :
- l'exécution pas à pas ;
- l'inspection des variables à chaque étape ;
- la pose de points d'arrêt (breakpoints) ;
- la navigation dans la pile d'appels.
4. Bonnes pratiques pour éviter les bugs
Section intitulée « 4. Bonnes pratiques pour éviter les bugs »| Pratique | Description |
|---|---|
| Nommer clairement | indice_max plutôt que x ou temp |
| Tester au fur et à mesure | Tester chaque fonction dès qu'elle est écrite |
| Écrire les tests d'abord | Définir les cas de test avant de coder (TDD) |
| Limiter la portée | Éviter les variables globales |
| Documenter | Docstrings pour chaque fonction |
| Utiliser des assertions | Vérifier les préconditions |
| Copier les mutables | Ne pas modifier involontairement les listes passées en argument |
| Éviter la comparaison de flottants | Utiliser une tolérance (epsilon) |
À retenir
Section intitulée « À retenir »| Type de bug | Exemple | Détection |
|---|---|---|
| Syntaxe | Parenthèse manquante | Avant l'exécution |
| Exécution | Division par zéro, index hors limites | Pendant l'exécution (exception) |
| Logique | Résultat faux, condition non exhaustive | Par les tests |
| Typage | "5" + 3 | TypeError à l'exécution |
| Effet de bord | Modification involontaire d'une liste | Par les tests |
| Off-by-one | < au lieu de <=, range(n) vs range(n+1) | Par les tests |
| Flottants | 0.1 + 0.2 != 0.3 | Comparaison avec epsilon |
© 2026 Corentin Dupont - LyCode
Créé avec Astro Starlight