Updated first chapter slides. Added new questions in the new training section.
5.3 KiB
title, author
title | author |
---|---|
Le droit aux erreurs | Steve Kossouho |
Le droit aux erreurs
Exceptions
En Python, une [exception]{.naming} est une erreur qui se produit pendant l'exécution de votre code. En tant que développeur, vous pouvez intercepter une exception, et dire à Python ce que vous souhaitez faire afin d'empêcher le programme de se terminer prématurément si ce n'est pas nécessaire.
Jargon des exceptions
- [Lever une exception]{.naming} : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script.
- [Traceback]{.naming} : Texte qui apparaît dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception.
Les exceptions levées par Python sont d'un type qui dépend de l'erreur rencontrée (ex. TypeError
{.python}).
Tous ces types font partie d'une hiérarchie dont le type le plus générique est nommé Exception
.
Théoriquement, un développeur peut créer son propre type d'exception lorsqu'il développe des bibliothèques.
Exemple de gestion d'exception
Dans l'exemple ci-dessous, on effectue une division par zéro, ce qui est toujours une erreur, mais on pourrait accéder à un mauvais index de liste, à une clé de dictionnaire inexistante, ou encore à un fichier verrouillé…
try:
resultat = 15 / 0 # erreur évidente pour l'exemple
print("Cette ligne ne sera jamais exécutée.")
except ZeroDivisionError: # Ici, on intercepte spécifiquement le type d'erreur produit par la division
print("Le résultat n'a pas pu être calculé.")
print("Fin du programme.")
Gestion des erreurs de division par zéro
Mauvaise pratique sur les exceptions
Il est ardemment déconseillé d'utiliser directement la classe Exception
{.python} (ou ne rien préciser, d'ailleurs) avec la clause except
{.python};
une clause trop générique intercepte tous les problèmes rencontrés dans le bloc try
{.python}.
Dans certains cas, cela vous fera manquer des erreurs que vous ne souhaitez pas traiter avec le même bloc except
{.python}.
Une règle d'or de Python indique que dans le cas où vous masquez tous les types d'exception sans distinction, vous ne devez jamais le faire silencieusement; affichez le problème ou consignez-le quelque part :
import traceback
try:
print(15 / 0)
except Exception: # ou except:
traceback.print_exc() # Affiche le traceback dans la console sans planter
Un bloc except
, plusieurs exceptions
On peut même avoir des blocs except
{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit d'indiquer
un tuple de classes d'exceptions à la clause except
{.python} :
try:
pass # ou faire autre chose
except (TypeError, ValueError):
pass
Un bloc try
, plusieurs gestions
On peut, à l'instar de la structure if/elif/else
, faire suivre le bloc try
{.python} de
plusieurs blocs except
{.python} :
try:
print("Code à essayer")
except ValueError:
print("Code pour ValueError")
except TypeError:
print("Code pour TypeError")
Python évaluera la structure de haut en bas. Si une erreur se produit dans le bloc try
{.python},
Python évaluera d'abord le premier bloc except
{.python}, de la même manière que pour toutes les structures de code.
Si aucun des blocs except
{.python} ne gère précisément l'erreur qui se produit dans le bloc try
{.python},
alors l'interpréteur Python plante avec un traceback dans la console, comme attendu.
try:
1 / 0
except TypeError: # pas la bonne exception
pass
except NameError: # pas la bonne exception non plus
pass
Code exécuté si tout se passe bien
La structure try
{.python}...except
{.python} peut être accompagnée d'un bloc else
{.python}. Ce bloc
sera exécuté si aucun des blocs except
{.python} précédents n'a été exécuté (comme dans une structure if
{.python}) :
try:
value = input("Saisissez un nombre entier : ")
value = int(value)
except ValueError:
value = None
else:
# Exécuté si le bloc try n'est pas interrompu par une erreur
print(f"Merci, la valeur est de {value}.")
Exécution garantie
Pour finir, il existe un bloc finally
{.python}, dont le bloc est toujours exécuté, même si le programme doit planter :
try:
15 / 0
except KeyError:
pass
finally:
print("Toujours exécuté")
En général, on imagine l'utiliser lorsqu'on souhaite penser à toujours libérer une ressource (connexion, fichier etc.)
Lever une exception
On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer. C'est généralement le cas lorsque l'on développe une bibliothèque utilisable par d'autres développeurs.
def do_something(value):
if not isinstance(value, int): # si value n'est pas un entier
raise TypeError("Value must be an integer.")