La pluie crépitait sur le toit en tôle de l'entrepôt. J'avais mis en place un système propre. Un plan infaillible. Mais l'infailibilité est un mything. Ce qui compte, c'est comment on gère l'imprévu. Le bruit sourd d'une porte qu'on enfonce. Le grésillement d'une radio qui tombe sur la mauvaise fréquence. En Python, ce sont les exceptions. Et celui qui ne sait pas les gérer ne survit pas longtemps.
Exceptions
Une exception, c'est le monde qui vous rappelle à l'ordre. Une erreur qui interrompt le flux normal. Python vous en jette une à la figure quand quelque chose ne va pas.
# Exemple d'exception classique : la division par zéro
montant_par_personne = butin_total / nombre_complices
# Si `nombre_complices` vaut zéro... Boom. ZeroDivisionError.
D'autres classiques : ValueError (une valeur inappropriée), TypeError (un mauvais type), KeyError (une clé absente d'un dictionnaire), FileNotFoundError (un fichier qui a disparu). Chacune est un signal d'alarme différent. Il faut savoir les reconnaître.
try / except / finally
Le système de pare-balles du code. On tente une opération risquée dans try. Si ça explose, on attrape l'exception dans except. Et quoi qu'il arrive, on exécute le bloc finally.
def ouvrir_coffre(code):
"""
Tente d'ouvrir un coffre sécurisé.
"""
coffre = None
try:
print(f"Tentative avec le code: {code}")
coffre = connecter_au_coffre(code) # Opération risquée
contenu = extraire_contenu(coffre)
return contenu
except CodeInvalideError:
print("Le code est invalide. Alerte silencieuse déclenchée.")
declencher_alerte_silencieuse()
return None
except SystemeVerrouilleError as err:
print(f"Système verrouillé. Délai: {err.delai} minutes.")
planifier_nouvelle_tentative(err.delai)
return None
except Exception as e:
# Attrape toute autre exception inattendue
print(f"Erreur inconnue: {e}. Nettoyage en cours.")
return None
finally:
# TOUJOURS exécuté, succès ou échec
print("Nettoyage des traces de connexion.")
if coffre:
deconnecter(coffre)
Le bloc except peut être spécifique. On peut attraper différents types d'erreurs et réagir différemment. Le finally, lui, est l'étape de nettoyage. Quoi qu'il se passe - que le coffre s'ouvre, que la police débarque, que le bâtiment prenne feu - le finally s'exécute. Pour effacer les empreintes, détruire les preuves, couper les liens.
Exceptions personnalisées
Parfois, les exceptions natives ne suffisent pas. Il faut créer les siennes. Des erreurs qui parlent votre langue. Celles de votre métier.
class OperationCompromiseError(Exception):
"""Levée quand une opération est découverte et compromise."""
def __init__(self, message, localisation, niveau_urgence):
super().__init__(message)
self.localisation = localisation
self.niveau_urgence = niveau_urgence
class ContactPerduError(Exception):
"""Levée quand un contact disparaît sans procédure de rupture."""
pass
# Utilisation :
def contacter_informateur(pseudo):
if pseudo not dans_reseau_actif:
# On lève NOTRE exception
raise ContactPerduError(f"{pseudo} hors réseau. Protocole 'Fantasme' activé.")
# ... suite de la fonction ...
Créer ses propres exceptions, c'est structurer ses échecs. C'est catégoriser les menaces. Quand vous levez une OperationCompromiseError, vous savez immédiatement de quoi il s'agit, quelles données sauver, quel protocole de fuite activer.
Le plan avait effectivement déraillé. L'alarme silencieuse que j'avais placée dans le système except s'est déclenchée. Pas de panique. Le bloc finally a fait son travail : brûler les carnets, effacer les logs, fermer les connexions.
Je suis sorti par l'arrière, le col de mon manteau relevé. La gestion des erreurs, ce n'est pas éviter la chute. C'est savoir atterrir. C'est avoir préparé la corde de rappel, le parachute, la sortie secrète.
Dans notre monde, le succès n'est pas l'absence d'échecs. C'est la capacité à les transformer en simples... perturbations. Contrôlées.
Prévoir le pire pour rester en vie.