ProgrammationDéveloppeur Backend

Décrivez les mécanismes de gestion des exceptions en Python. Comment fonctionne le bloc try/except/finally, à quoi sert raise et quels pièges rencontrés fréquemment ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Python, la gestion des exceptions est mise en œuvre à travers les constructions try/except/else/finally et l'opérateur raise.

try définit un bloc de code protégé. Si une exception se produit à l'intérieur, le contrôle est transféré au bloc except correspondant le plus proche. S'il n'y a pas d'exception, le bloc else est exécuté, s'il existe. Le bloc finally est toujours exécuté — qu'une exception se soit produite ou non (par exemple, pour libérer des ressources).

L'opérateur raise déclenche une exception explicitement ou relance l'actuelle (dans le bloc except sans spécification de type).

Exemple :

try: x = 1 / 0 except ZeroDivisionError as e: print(f"Erreur : {e}") else: print("Pas d'erreur") finally: print("Toujours exécuté")

Sortie :

Erreur : division par zéro
Toujours exécuté

Subtilités :

  • Lors des gestionnaires imbriqués, l'ordre des except est important : des types spécifiques aux plus généraux (sinon, les spécifiques ne seront pas traités).
  • Le bloc finally ne peut pas empêcher la relance d'une exception (si un raise est ajouté à l'intérieur du finally — la dernière erreur est applicable).

Question piège

Question : « Que se passe-t-il si dans le bloc try et dans le finally, vous appelez raise avec des exceptions différentes ? »

Réponse : L'exception du finally "couvre" l'exception du try : ce qui sortira sera celui qui a été déclenché dans le finally.

def foo(): try: raise ValueError("dans try") finally: raise IndexError("dans finally") try: foo() except Exception as e: print(repr(e)) # Affichera : IndexError('dans finally')

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

Dans un processus ETL, la connexion à la base était systématiquement fermée dans le bloc finally, mais on oubliait que cela pouvait déclencher une exception (par exemple, si la connexion était déjà fermée). Au final — une exception "cachée" dans finally absorbait complètement l'exception du code principal, rendant le débogage beaucoup plus difficile.


Histoire

Des chaînes de plusieurs except ont été utilisées : un except Exception général au-dessus des spécifiques. Par conséquent, tous les except spécifiques restaient "morts" — les exceptions à faible niveau n'étaient pas attrapées séparément, ce qui compliquait le traitement des erreurs spécifiques.


Histoire

Dans un service web, dans le except du bloc, on oubliait de relancer l'exception via "raise", en journalisant l'erreur, mais en permettant à l'exécution de continuer. Au final, les véritables erreurs "se perdaient", et le programme continuait à fonctionner avec un état incorrect.