Gestion des erreurs#
courant
Principes#
- Attraper l'exception la plus précise possible, jamais
except:nu. - Ne pas utiliser les exceptions pour du contrôle de flux ordinaire lorsque la situation est prévisible.
- Une exception attrapée doit être traitée ou relevée (
raise) — jamais silencieusement ignorée (except: pass).
# À éviter : exception inutile pour une absence normale de clé
try:
valeur = d["cle"]
except KeyError:
valeur = None
# Préférable : méthode dédiée
valeur = d.get("cle")
EAFP vs LBYL#
Python privilégie idiomatiquement EAFP (Easier to Ask Forgiveness than Permission) plutôt que LBYL (Look Before You Leap), particulièrement pour la conversion de données et les opérations d'I/O.
# LBYL (Look Before You Leap) : on vérifie avant d'agir (souvent fragile ou redondant)
if saisie.lstrip("-").isdigit():
valeur = int(saisie)
else:
valeur = 0
# EAFP (Easier to Ask Forgiveness than Permission) : idiomatique en Python
try:
valeur = int(saisie)
except ValueError:
valeur = 0
Exceptions personnalisées#
Créer une hiérarchie propre à l'application plutôt que de réutiliser Exception partout.
class ErreurMetier(Exception):
"""Base pour les erreurs métier de l'application."""
class StockInsuffisantError(ErreurMetier):
pass
Chaînage explicite#
try:
charger_config()
except FileNotFoundError as e:
raise ErreurMetier("configuration manquante") from e # préserve la cause originale
Ne pas masquer les erreurs de programmation#
try:
resultat = risque()
except ValueError:
...
# Une KeyError ou TypeError imprévue remonte normalement : ne pas mettre
# "except Exception" par défaut sans bonne raison, cela masque les bugs.
Logging plutôt que print pour les erreurs en production#
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s — %(message)s",
)
logger = logging.getLogger(__name__)
try:
traiter()
except ErreurMetier:
logger.exception("échec du traitement") # niveau ERROR + trace complète
Niveaux disponibles, du moins au plus grave : DEBUG, INFO, WARNING (défaut), ERROR, CRITICAL.