145 lines
4.5 KiB
Markdown
145 lines
4.5 KiB
Markdown
---
|
||
title: Le droit aux erreurs
|
||
author: Steve Kossouho
|
||
---
|
||
|
||
# Le droit aux erreurs
|
||
|
||
----
|
||
|
||
## Exceptions
|
||
|
||
En Python, une exception est une erreur qui se produit pendant l'exécution de votre code. En tant que développeur, vous pouvez choisir ce que vous souhaitez faire quand une exception se produit, plutôt que de laisser le programme s'arrêter avec un message d'erreur. Les exceptions s'opposent entre autres aux erreurs de syntaxe, où l'interpréteur n'est pas même en mesure d'exécuter votre code.
|
||
|
||
----
|
||
|
||
### Jargon des exceptions
|
||
|
||
- `Lever une exception` : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script. Les exceptions générées par Python sont d'un type qui dépend de l'erreur rencontrée. Elles font toutes partie d'une hiérarchie dont le type le plus générique est nommé `Exception`. (voir programmation orientée objet et hiérarchie des classes d'exception)
|
||
- `Traceback` : <span style="color:red">Texte qui apparaît</span> 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.
|
||
|
||
----
|
||
|
||
### Exemple d'exception
|
||
|
||
Dans l'exemple ci-dessous, on effectue une division par zéro, mais on pourrait accéder à un mauvais indice de liste, une mauvaise clé de dictionnaire, un fichier verrouillé…
|
||
|
||
```{.python .numberLines}
|
||
try:
|
||
15 / 0 # erreur évidente pour l'exemple
|
||
except ZeroDivisionError:
|
||
pass
|
||
```
|
||
|
||
Gestion des erreurs de division par zéro
|
||
|
||
----
|
||
|
||

|
||
|
||
----
|
||
|
||
### À ne pas faire
|
||
|
||
Il est déconseillé d'utiliser directement la classe `Exception` (ou rien, d'ailleurs) avec la clause `except`;
|
||
ceci a pour effet de pousser votre code à réagir exactement de la même manière pour tous les cas de figure.
|
||
Si vous le tentez malgré tout, affichez ou conservez le traceback, vous me remercierez plus tard :
|
||
|
||
```{.python .numberLines}
|
||
import traceback
|
||
|
||
try:
|
||
print(15 / 0)
|
||
except Exception: # ou except:
|
||
traceback.print_exc() # Affiche le traceback dans la console
|
||
```
|
||
|
||
Voir [antipattern sur les exceptions pour plus d'info](https://realpython.com/the-most-diabolical-python-antipattern/)
|
||
|
||
----
|
||
|
||
### 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 de les indiquer dans un tuple :
|
||
|
||
```{.python .numberLines}
|
||
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} :
|
||
|
||
```{.python .numberLines}
|
||
try:
|
||
print("Code à essayer")
|
||
except ValueError:
|
||
print("Code pour ValueError")
|
||
except TypeError:
|
||
print("Code pour TypeError")
|
||
```
|
||
|
||
----
|
||
|
||
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.
|
||
|
||
```{.python .numberLines}
|
||
try:
|
||
1 / 0
|
||
except NameError:
|
||
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}) :
|
||
|
||
```{.python .numberLines}
|
||
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 :
|
||
|
||
```{.python .numberLines}
|
||
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.)
|
||
|
||
----
|
||
|
||
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 fournit une API utilisable par d'autres développeurs.
|
||
|
||
```{.python .numberLines}
|
||
def do_something(value):
|
||
if not isinstance(value, int): # si value n'est pas un entier
|
||
raise TypeError("Value must be an integer.")
|
||
```
|