2.25. Gestion des erreurs#

La plupart des problèmes d’exécution en Python se manifestent sous forme d”exceptions – une manière nommée et structurée de signaler qu’un problème est survenu. ValueError, TypeError, KeyError, OSError, MemoryError en sont autant d’exemples ; chacune est une classe, et en lever une interrompt l’appel en cours pour chercher un gestionnaire dans le code environnant.

2.25.1. try / except#

Encadrez un bloc de code dans try pour intercepter toute exception qu’il lève :

try:
    n = int(input_text)
except ValueError:
    n = 0

Si la conversion int(...) échoue, le contrôle saute au bloc except au lieu de propager l’erreur plus loin. Si input_text était une chaîne d’entier valide, le bloc except est ignoré.

Un seul try peut comporter plusieurs blocs except, chacun interceptant un type d’erreur différent :

try:
    value = data[key]
except KeyError:
    value = None
except TypeError:
    value = -1

Python établit la correspondance dans l’ordre ; le premier dont la classe d’exception convient traite le problème. Intercepter Exception (la classe de base de presque tout) traite toute erreur ; réservez cela à la couche la plus externe d’un programme, où l’alternative serait un plantage.

Avertissement

Un except: nu (sans classe après le mot-clé) intercepte aussi KeyboardInterrupt – l’exception que l’IDE envoie lorsque vous appuyez sur son bouton stop pour interrompre un script en cours. Une boucle enveloppée dans un except: pass nu avalera l’interruption et continuera de tourner, ne laissant aucun moyen d’arrêter le script hormis une coupure d’alimentation.

Préférez except Exception: à un except: nu lorsque vous avez véritablement besoin d’intercepter largement. KeyboardInterrupt hérite de BaseException, et non de Exception, donc except Exception: laisse le bouton stop fonctionnel.

2.25.1.1. Inspecter l’exception#

Pour lire le message attaché à une exception, nommez-la avec as :

try:
    f = open("data.txt")
except OSError as e:
    print("could not open file:", e)

La variable liée par as n’est valide qu’à l’intérieur du bloc except.

2.25.2. else et finally#

Un bloc try dispose de deux ajouts facultatifs.

else ne s’exécute que lorsque le try s’est terminé sans rien lever :

try:
    value = compute()
except ValueError:
    print("bad input")
else:
    print("got", value)

Placer « ce qu’il faut faire en cas de succès » dans else garde le bloc try étroit – seule la ligne susceptible d’échouer appartient au try.

finally s’exécute à la fin quoi qu’il arrive – que le try ait réussi, qu’il ait levé une exception interceptée, ou qu’il en ait levé une sur le point de se propager :

try:
    do_work()
finally:
    cleanup()
Flow diagram showing the four possible paths through try / except / else / finally: success goes to else then finally; a caught exception goes to except then finally; an uncaught exception goes to finally then propagates.

finally s’exécute toujours. else ne s’exécute que sur le chemin sans exception.#

Pour la plupart des motifs acquisition/libération, préférez un gestionnaire de contexte à un couple try / finally – la ressource elle-même gère son propre nettoyage.

2.25.3. Exceptions intégrées courantes#

Une courte liste des exceptions que vous rencontrerez souvent :

  • ValueError – type correct, valeur incorrecte (bytes([300]) – 300 est du bon type, mais hors de la plage d’octets valide 0..255).

  • TypeError – type totalement incorrect (len(42)).

  • KeyError – clé absente dans un dict.

  • IndexError – indice au-delà de la fin d’une séquence.

  • AttributeError – accès à un attribut inexistant ("abc".foo).

  • OSError – une défaillance du système de fichiers ou d’E/S.

  • MemoryError – plus de mémoire sur le tas. Sur un environnement d’exécution à mémoire contrainte, cela peut survenir lors d’un fonctionnement normal – pas seulement dans des cas pathologiques.