En Python, lorsqu’une erreur se produit ou qu’un cas particulier empêche (a priori) la suite du déroulement normal d’un programme ou d’une fonction, une exception est déclenchée
Attention : différent des erreurs de syntaxe
Utiliser une variable qui n’existe pas
Utiliser int()
sur quelque chose qui ne peut pas être converti en entier
Diviser un nombre par zero
Diviser un nombre par une chaine de caractère
Tenter d’accéder à un élément d’une liste qui n’existe pas
Tenter d’ouvrir un fichier qui n’existe pas ou qu’on ne peut pas lire
Tenter de télêcharger des données sans être connecté à internet
etc…
Une exception a un type (c’est un objet d’un classe d’exception -> cf. Partie 3):
Exception
, ValueError
, IndexError
, TypeError
, ZeroDivisionError
, …Lorsqu’une exception interrompt le programme, l’interpréteur affiche la stacktrace (TraceBack) qui contient des informations pour comprendre quand et pourquoi l’exception s’est produite.
Traceback (most recent call last):
File "coucou.py", line 3, in <module>
print(coucou)
NameError: name 'coucou' is not defined
# python3 test_int.py
Tapez un entier entre 1 et 3: truc
Traceback (most recent call last):
File "test_int.py", line 8, in <module>
demander_nombre()
File "test_int.py", line 4, in demander_nombre
r = int(input("Tape un entier entre 1 et 3: "))
ValueError: invalid literal for int() with base 10: 'truc'
Souvent une exception est due à une entrée utilisateur incorrecte (comme ici) mais pas toujours.
raise
Il est possible de déclencher ses propres exceptions à l’aide de raise
def max(liste_entiers):
if liste_entiers == []:
raise Exception("max() ne peut pas fonctionner sur une liste vide!")
(Ici, le type utilisé est le type générique Exception
)
Autre exemple:
def envoyer_mail(destinataire, sujet, contenu):
if '@' not in destinataire:
raise Exception('Une adresse mail doit comporter un @ !')
(Ici, le type utilisé est le type générique Exception
)
try
/except
De manière générale dans un programme, il peut y’avoir beaucoup de manipulation dont on sait qu’elles peuvent échouer pour un nombre de raisons trop grandes à lister …
Par exemple : écrire dans un fichier
Autre exemple : aller chercher une information sur internet
En Python, il est courant d'« essayer » des opérations puis de gérer les exceptions si elles surviennent.
On utilise pour cela des try: ... except: ...
.
reponse = input("Entrez un entier svp !")
try:
n = int(reponse)
except:
raise Exception("Ce n'est pas un entier !")
reponse = input("Entrez un entier svp !")
try:
n = int(reponse)
except:
n = -1
while True:
reponse = input("Entrez un entier svp !")
try:
n = int(reponse)
break
except:
# Faire en sorte de boucler pour reposer la question à l'utilisateur ...
print("Ce n'est pas un entier !")
continue
def can_be_converted_to_int(stuff):
try:
int(stuff)
except:
return False
return True
can_be_converted_to_int("3") # -> True
can_be_converted_to_int("abcd") # -> False
Traduction “on essaye et puis on voit et on gère les dégats”. (ça se discute)
Il est possible d’utiliser des assert
ions pour expliciter certaines hypothèses
faites pendant l’écriture du code. Si elles ne sont pas remplies, une exception est déclenchée.
Un peu comme un "if not condition raise error"
.
def max(liste_entiers):
assert liste_entiers != [], "max() ne peut pas fonctionner sur une liste vide!"
(assert toto
est équivalent à if not toto: raise Exception()
)
def distance(x=0, y=0):
assert isinstance(x, (int, float)), "Cette fonction ne prends que des int ou float en argument !"
assert isinstance(y, (int, float)), "Cette fonction ne prends que des int ou float en argument !"
return racine_carree(x*x + y*y)
def some_function(n):
assert n, "Cette fonction n'accepte pas 0 ou None comme argument !"
assert n % 2 == 0, "Cette fonction ne prends que des entiers pairs en argument !"
[...]
En pratique, l’une des utilisations les plus courantes de assert
est l’écriture de tests unitaires qui permettent de valider qu’une fonction marche dans tous les cas (et continue à marcher si on la modifie)
Dans votre application:
def trier(liste_entiers):
# on définie le comportement de la fonction
Dans les tests (fichier à part):
assert trier([15, 8, 4, 42, 23, 16]) == [4, 8, 15, 16, 23, 42]
assert trier([0, 82, 4, -21, 2]) == [-21, 0, 2, 4, 82]
assert trier([-7, -3, 0]) == [-7, -3, 0]
assert trier([]) == []
Cf. Chapitre 19
Attention : dans les exemples suivant je dois penser au cas où resultat
peut valoir None
Je soupçonne fortemment que
ma_liste
puisse ne pas être une liste ou puisse être vide
if not isinstance(ma_liste, list) or ma_liste == []:
resultat = None
else:
resultat = max(ma_liste)
Ça devrait marcher, mais j’ai un doute …
try:
resultat = max(ma_liste)
except ValueError as e:
print("Warning : peut-etre que ma_liste n'etait pas une liste non-vide ?")
resultat = None
Normalement
ma_liste
est une liste non-vide, sinon il y a un très gros problème avant dans le programme…
assert isinstance(ma_liste, list) and ma_liste != []
resultat = max(ma_liste)
Dans ce cas la fonction