2.4Gestion des erreurs & exceptions
L'essentiel en 30 secondes
- Encadrer le risqué précis : try sur la conversion, le fichier, le réseau — jamais tout le programme.
- Attraper précis, pas large : except ValueError/FileNotFoundError ciblé — except nu ou pass enterre les bugs.
- Signaler tôt et fort : raise pour vos invariants, else/finally à bon escient, logguer puis dégrader proprement.
Mini-cas filé — Nabil fiabilise l'import du mois
Dernier acte : l'import mensuel de Nabil plante au premier imprévu — export absent, montant non numérique, total divisé par zéro quand aucune vente. Les utilisateurs voient une trace rouge. Il fiabilise : conversion des montants en try/except ValueError avec redemande, ouverture en try/except FileNotFoundError avec message clair, division protégée contre ZeroDivisionError, montants négatifs refusés par raise dès la création de la Vente (2.3). Le reste remonte avec sa traceback : rien n'est silencé. L'import du niveau 2 est livré : données, texte, objets, erreurs maîtrisées.
Épilogue du fil rouge 2.1-2.3 : l'import de Nabil ne plante plus au premier imprévu.
1. L'exception n'est pas une catastrophe
ValueError, KeyError, FileNotFoundError, ZeroDivisionError : des objets informatifs, pas des insultes. try/except encadre le risqué précis (conversion d'une saisie, ouverture d'un fichier, division) — jamais tout le programme : attraper large cache les bugs. La traceback se lit de bas en haut : le type d'erreur puis la ligne fautive. Nabil l'applique : seule la conversion des montants est encadrée, pas tout l'import.
2. try/except/else/finally : chacun son rôle
try contient le risqué, except ValueError attrape un type précis avec un message utile, else exécute la suite si tout va bien, finally nettoie toujours (fermer, libérer — même en cas d'erreur). raise ValueError("...") signale vos propres invariants : un montant négatif est refusé tôt et fort, dès la création. Nabil refuse ainsi les montants négatifs dans __init__ : l'erreur est signalée à la source, pas trois fonctions plus loin.
3. Laisser filer ce qu'on ne traite pas
Règle d'or : on n'attrape que ce qu'on sait traiter (redemander, valeur par défaut, message clair). Le reste remonte avec sa traceback : le silencer avec except: pass enterre les bugs vivants — le pire réflexe. Un except nu masque tout, y compris ce que vous devriez voir. En production, on loggue puis on dégrade proprement (message à l'utilisateur, arrêt contrôlé). L'import de Nabil redemande les montants invalides, signale l'export absent — et laisse remonter l'inattendu.
Le saviez-vous ?
Un bug silencé travaille contre vous en silence.
🔎 Exemple concret — 🔎 Exemple concret — La saisie robuste de Nabil, sans silence
Le précis est rattrapé, le reste remonterait, comme chez Nabil :
def lire_montant(texte):
try:
montant = float(texte)
except ValueError:
raise ValueError(f"montant invalide : {texte!r}") from None
if montant < 0:
raise ValueError("montant négatif interdit")
return montant
try:
print(lire_montant("1250.5"))
except ValueError as e:
print(f"Erreur : {e}")
Lecture : ValueError ciblé, invariant signalé par raise, message utile.
Leçon : jamais de except: pass — il enterre les bugs vivants.
Vocabulaire de la section
- Exception
- Erreur survenant à l'exécution (ZeroDivisionError, ValueError, FileNotFoundError…) qui interrompt le programme si non gérée. Lue de bas en haut dans la traceback.
Exemple simple : L'export absent de Nabil lève FileNotFoundError.
Ce que ce n'est pas : une erreur de syntaxe qui empêche le démarrage.
Réflexe : plantage à l'exécution = exception à lire.
- try / except
- try contient le code risqué (bloc étroit) ; except attrape un TYPE PRÉCIS et exécute un traitement réel au lieu de planter.
Exemple simple : Nabil entoure float(montant) d'un except ValueError.
Ce que ce n'est pas : un except nu qui attrape tout sans traiter.
Réflexe : risqué précis = try + except ciblé.
- else / finally
- else : la suite si aucune erreur ; finally : exécuté DANS TOUS LES CAS, idéal pour libérer une ressource (fermer un fichier).
Exemple simple : Nabil affiche « import terminé » en finally.
Ce que ce n'est pas : un nettoyage qui ne tourne qu'en cas de succès.
Réflexe : nettoyage garanti = finally.
- raise
- Lève volontairement une exception pour signaler une situation anormale (invariant violé) : échouer tôt et fort, à la source.
Exemple simple : La Vente de Nabil refuse les montants négatifs par raise.
Ce que ce n'est pas : un retour silencieux qui laisse passer des données fausses.
Réflexe : invariant violé = raise immédiat.
- Traceback
- La trace d'erreur affichée par Python : lue de bas en haut, elle indique le type d'erreur et la ligne fautive. À logguer, pas à masquer.
Exemple simple : Nabil lit le bas de la traceback pour trouver la conversion fautive.
Ce que ce n'est pas : un message masqué par except: pass.
Réflexe : traceback = lire le bas, corriger la ligne.
En pratique — En pratique — Fiabiliser un programme avec try/except
- Demandez un montant et convertissez-le : entourez float() d'un try/except ValueError qui redemande en cas de saisie non numérique.
- Gérez une moyenne en attrapant ZeroDivisionError (aucune vente) avec un message clair au lieu d'un plantage.
- Ouvrez l'export en try/except FileNotFoundError ; ajoutez un finally qui affiche « import terminé » dans tous les cas.
- Écrivez une fonction qui lève (raise) ValueError pour un montant négatif, et testez-la avec try/except.
Script prêt à dire — justifier le ciblage en revue de code (30 s)
« Pour l'import de Nabil, chaque try est étroit : conversion en ValueError, export en FileNotFoundError, avec un vrai traitement derrière. Les montants négatifs partent en raise dès la création. Et pas de except pass : ce qu'on ne sait pas traiter remonte et se loggue — on n'enterre jamais un bug. »
À dire en montrant un except nu remplacé par deux except ciblés.
Modèle copier-coller — import fiabilisé de bout en bout
import json
from pathlib import Path
def lire_montant(texte):
montant = float(texte)
if montant < 0:
raise ValueError("montant négatif interdit")
return montant
fichier = Path("ventes.json")
try:
lignes = json.loads(fichier.read_text(encoding="utf-8"))
except FileNotFoundError:
print("Export introuvable : vérifiez ventes.json")
lignes = []
try:
montants = [lire_montant(str(l)) for l in lignes]
except ValueError as e:
print(f"Ligne invalide ignorée : {e}")
montants = []
else:
print(f"{len(montants)} montants lus")
finally:
print("import terminé")
Saisie à redemander
Le montant tapé par Nabil passe en float() ciblé : ValueError redemande, le reste remonte.
Export absent
Le fichier du mois manque : FileNotFoundError affiche un message clair au lieu d'une trace rouge.
Moyenne sans vente
Aucune vente à Alger ce jour : ZeroDivisionError intercepté, « pas de moyenne » affiché.
Montant interdit
Un montant négatif déclenche raise dès la Vente : échouer tôt, signaler à la source.
✓ Bonnes pratiques
- Encadrer le risqué précis avec des blocs try étroits.
- Attraper des types précis avec un vrai traitement (else/finally à bon escient).
- Lever avec raise pour les invariants ; logguer puis dégrader proprement.
✗ Pièges fréquents
- Utiliser except: nu ou except: pass (masque et enterre les bugs).
- Encadrer tout le programme dans un seul try.
- Silencer au lieu de traiter (continuer avec des données fausses).
Points clés à retenir
- try/except attrape les erreurs au lieu de laisser le programme planter — bloc étroit sur le risqué.
- Ciblez le type d'erreur (ValueError, FileNotFoundError…) plutôt qu'un except vide.
- else = suite si OK ; finally s'exécute toujours : parfait pour libérer une ressource.
- raise lève une exception pour signaler une situation anormale ; SyntaxError ne se gère pas avec try.
Défi 48h — appliquez demain
Fiabilisez un vrai script (celui de Nabil ou le vôtre) : try étroit + except ciblé sur chaque point fragile (conversion, fichier, division), un raise pour un invariant, un finally réel — et chassez tout except: pass.
- Je peux expliquer try/except/else/finally et le rôle de chacun.
- Je sais attraper précis et lever avec raise pour mes invariants.
- J'ai supprimé tout except nu ou silencé de mon code.
Questions fréquentes
Faut-il attraper toutes les erreurs avec un except général ?
Non : un « except: » nu masque tout, y compris des bugs que vous devriez voir. Attrapez des exceptions ciblées (except ValueError) pour ne gérer que ce que vous anticipez, et laissez remonter le reste. C'est une règle d'or de la fiabilité.
Quelle différence entre une erreur de syntaxe et une exception ?
Une erreur de syntaxe (SyntaxError) empêche le programme de démarrer : le code est mal écrit. Une exception survient à l'exécution d'un code par ailleurs valide (fichier absent, division par zéro). Seules les exceptions se gèrent avec try/except.
Que faut-il éviter absolument en gestion d'erreurs ?