Exceptions & Débogage

Gérer
les erreurs

Hiérarchie des exceptions, try/except, exceptions personnalisées, logging et débogueur.

Hiérarchie des exceptions

Toutes les exceptions héritent de BaseException. Attraper une classe parente attrape aussi toutes les classes filles.

BaseException
├── SystemExit
├── KeyboardInterrupt
└── Exception ← attraper celle-ci
├── ValueError
├── TypeError
├── KeyError
├── IndexError
├── AttributeError
├── FileNotFoundError
├── ZeroDivisionError
├── StopIteration
├── OSError
├── FileNotFoundError
└── PermissionError
└── ArithmeticError
├── ZeroDivisionError
└── OverflowError
⚠️

Ne jamais faire except: ou except Exception: de façon aveugle — cela masque les erreurs. Toujours attraper le type d'exception le plus précis possible.

ℹ️

Ne jamais attraper SystemExit ni KeyboardInterrupt (Ctrl+C) — ils ne sont pas des erreurs de programme.

try / except / else / finally

Python — structure complète
try:
    # Code susceptible de lever une exception
    résultat = int(input("Entrez un nombre : "))
    valeur = 100 / résultat

except ValueError:
    # Saisie non convertible en int
    print("Ce n'est pas un nombre valide.")

except ZeroDivisionError:
    # Division par zéro
    print("Division par zéro impossible.")

except (OSError, IOError) as e:
    # Attraper plusieurs types, récupérer l'objet
    print(f"Erreur I/O : {e}")

else:
    # Exécuté SEULEMENT si aucune exception
    print(f"Résultat : {valeur}")

finally:
    # TOUJOURS exécuté (nettoyage)
    print("Fin du bloc.")
BlocQuand s'exécute-t-il
tryToujours en premier
exceptSi exception correspondante
elseSi aucune exception dans try
finallyToujours, exception ou non
💡

Mettre le code "succès" dans else plutôt que dans try — cela évite d'attraper accidentellement les exceptions que else pourrait lever.

Re-lever une exception
try:
    données = charger_fichier()
except FileNotFoundError as e:
    print(f"[LOG] Fichier manquant : {e}")
    raise   # re-lever SANS perdre la trace

Lever une exception

Python
# Lever une exception standard
def diviser(a, b):
    if b == 0:
        raise ValueError("Le diviseur ne peut pas être zéro")
    return a / b

# Chaîner les exceptions (Python 3)
try:
    résultat = int("abc")
except ValueError as e:
    raise RuntimeError("Échec du traitement") from e
    # La traceback montrera les deux erreurs

# Supprimer la chaîne (si non pertinente)
raise RuntimeError("Échec") from None

Exceptions personnalisées

Créer ses propres exceptions améliore la lisibilité et permet des traitements spécifiques.

Python
# Hiérarchie personnalisée
class AppErreur(Exception):
    """Classe de base pour les erreurs de l'application."""
    pass

class ErreurValidation(AppErreur):
    def __init__(self, champ: str, valeur, message: str):
        self.champ = champ
        self.valeur = valeur
        super().__init__(f"[{champ}={valeur}] {message}")

class ErreurBD(AppErreur):
    def __init__(self, requête: str, cause=None):
        self.requête = requête
        super().__init__(f"Échec requête : {requête}")
        if cause: self.__cause__ = cause

# Utilisation
def valider_age(age: int):
    if not (0 <= age <= 150):
        raise ErreurValidation("age", age, "doit être entre 0 et 150")

try:
    valider_age(-5)
except ErreurValidation as e:
    print(f"Champ invalide : {e.champ}")  # "age"
    print(e)  # "[age=-5] doit être entre 0 et 150"

Context managers — with

Python — usage
# Fichiers — fermeture automatique
with open("data.txt") as f:
    contenu = f.read()
# f est fermé ici, même si exception

# Plusieurs contextes
with open("in.txt") as src, \
     open("out.txt", "w") as dst:
    dst.write(src.read())
Python — créer un context manager
from contextlib import contextmanager

@contextmanager
def chrono(label):
    import time
    début = time.perf_counter()
    try:
        yield         # ← le bloc with s'exécute ici
    finally:
        durée = time.perf_counter() - début
        print(f"{label}: {durée:.3f}s")

with chrono("Traitement"):
    traiter_données()

Cheat sheet

Structure try

try / exceptAttraper une erreur
except X as eRécupérer l'objet
elseSi aucune erreur
finallyToujours exécuté
raiseLever / re-lever
raise X from YChaîner

Exceptions courantes

ValueErrorValeur incorrecte
TypeErrorMauvais type
KeyErrorClé dict absente
IndexErrorIndex hors limite
AttributeErrorAttribut inexistant
FileNotFoundErrorFichier absent

Bonnes pratiques

Précisexcept ValueError, pas Exception
Logginglogger.exception() dans except
CustomHériter de Exception
Contextewith open() plutôt que try/finally
Re-leverraise (sans arg) préserve la trace
Aller plus loin

Pour les stratégies de débogage avancées (pdb, VS Code debugger, print/logging, erreurs fréquentes Python/JS/C), consultez la page dédiée :

🐛 Débogage — Guide complet