2.4 · Gestion des erreurs & exceptions

Niveau 2 · Structures de données & POO

2.4Gestion des erreurs & exceptions

Objectif : Gérer try/except/finally et créer ses propres exceptions.
Temps estimé : 12 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

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.

Erreur d'interprétation fréquente : « Pour être sûr, j'attrape tout avec except: et je mets pass ». Non, c'est le plus sûr moyen de ne plus rien voir : un except nu attrape même les bugs de votre propre code et pass les enterre — le programme continue avec des données fausses, sans aucun signal. La règle de Nabil : except ciblé (ValueError, FileNotFoundError) + traitement réel (redemander, défaut, message) ; ce qu'on ne sait pas traiter remonte et se loggue.
Erreurs maîtrisées Encadrer, traiter, signaler try (risqué) Conversion,fichier — bloc étroitexcept (précis) Type ciblé+ traitement réelraise/log (signaler) Invariantstôt, inattendu qui remonte
Encadrer, traiter, signaler
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Nabil encadre le RISQUÉ PRÉCIS avec try (conversion des montants, ouverture de l'export) — jamais tout le programme. 2) Il attrape PRÉCIS (except ValueError/FileNotFoundError) avec un traitement réel : redemande, message clair, else pour la suite, finally pour nettoyer. 3) Il SIGNALE tôt avec raise (montant négatif refusé dès __init__) et laisse filer l'inattendu avec sa traceback, loggué — jamais de except: pass. Leçon : échouer tôt et fort, silencer jamais.

Le saviez-vous ?

Nabil a un jour écrit « except: pass » pour faire taire une erreur — et son rapport d'Alger est resté à zéro pendant une semaine sans alerter personne.
Vrai : silencer une erreur enterre le bug vivant — on attrape précis et on traite.

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

  1. Demandez un montant et convertissez-le : entourez float() d'un try/except ValueError qui redemande en cas de saisie non numérique.
  2. Gérez une moyenne en attrapant ZeroDivisionError (aucune vente) avec un message clair au lieu d'un plantage.
  3. Ouvrez l'export en try/except FileNotFoundError ; ajoutez un finally qui affiche « import terminé » dans tous les cas.
  4. Écrivez une fonction qui lève (raise) ValueError pour un montant négatif, et testez-la avec try/except.
Vous anticipez les erreurs avec try/except/finally et levez vos propres exceptions : vos programmes deviennent robustes face à l'imprévu.

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.

Checklist sortie de section
  • 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.
Auto-évaluation 1-5 : est-ce que mes try sont étroits et ciblés ?est-ce que je signale tôt au lieu de silencer ?

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.

Vérifiez votre compréhension

Que faut-il éviter absolument en gestion d'erreurs ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 2Questions inédites et durcies pour valider vos acquis