Retourner à : Python pour débutants
Savoir écrire des programmes qui font ce qu’on leur demande, c’est top. Écrire des programmes qui ne crashent pas lorsque leur exécution dévie de ce qui a été prévu peut être tout aussi simple, à condition de savoir gérer ces cas exceptionnels. Dans ce chapitre, on va voir ce que sont les exceptions en Python, pourquoi elles existent, et comment les utiliser correctement pour rendre notre code plus robuste et plus fiable.
Pour cela nous allons :
- définir ce qu’est une exception
- voir comment gérer des exceptions avec try / except
- voir comment utiliser les instructions else et finally avec un try / except
- pour finir, nous verrons également comment créer nos propres exceptions
Préparation
Pour suivre ce cours, vous devrez créer un dossier input et un dossier output dans le même dossier ou vous écrirez votre fichier de code Python (main.py). Dans le dossier input il faudra que vous écriviez un fichier sample.txt contenant plusieurs lignes de texte.
Si vous souhaitez avoir le même résultat que ceux illustrés dans les exercices ci-dessous, vous pouvez copier le contenu du fichier que vous retrouverez ci-dessous :
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.Définition
Jusqu’à présent nous avons vu comment créer des programmes Python relativement simple, en partant du principe que tout se passe comme nous l’avons prévu pendant l’execution de celui-ci. Malheureusement, en pratique des choses peuvent mal tourner :
- Un utilisateur auquel nous demandons son âge peut tout à fait rentrer une texte dans le terminal, ce qui ferra planter notre programme si nous essayons de convertir cette chaîne de caractères en nombre.
- Notre programme pourrait essayer de lire un fichier qui n’existe pas, ou pour lequel il n’a pas les droits de lecture.
Et là, je ne site que deux exemples, mais il y a encore beaucoup d’autres choses qui pourraient mal tourner pendant l’exécution d’un programme. Ces situations, ou un programme fait fasse à une situation inattendue ont un nom : les exceptions.
Avant de voir comment traiter les exceptions, regardons à quoi une telle exception ressemble. Pour cela considérons le programme suivant :
age_text = input("Quel est votre âge ? ")
age = int(age_text)
print(f"Vous avez {age} ans !")Comme vous le voyez, ce code demande à l’utilisateur d’entrer son âge, s’attend à un nombre entier et utilise la méthode int() pour convertir ce nombre en variable du type int. Maintenant exécutons ce programme et renseignons un texte en tant qu’input, au lieu d’un nombre :

Ici on voit plusieurs choses :
- Python a arrêté l’exécution de notre programme
- On a un message d’erreur « ValueError: invalid literal for int() with base 10: ‘trente’« .
- Et on a ce qu’on appel une stack trace qui indique où l’erreur s’est produite. Ici l’erreur c’est produite à la ligne 2 de notre fichier main.py.
Dans cette exemple la stack trace est très simple car nous n’utilisons pas de fonctions. Mais si nous modifions le code afin que l’âge soit demandé dans un fonction, comme ceci :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
age = ask_age()
print(f"Vous avez {age} ans !")Maintenant, si nous exécutons de nouveau notre programme, en entrant un texte invalide, nous obtenons la stack trace suivante :

Comme vous pouvez le voir, la stack trace, ne nous indique pas uniquement l’endroit ou l’erreur s’est produite, mais également les différents appels à fonctions qui ont menés à l’erreur. Ici on voit que l’erreur vient d’un appel à la fonction ask_age(), fait à la ligne 5 du fichier main.py, et l’erreur à eu lieu au moment où la méthode ask_age() a essayé de convertir le nombre en entier, à la ligne 3 du fichier main.py.
Le block try / except
Comme nous venons de le voir, si un problème inattendu survient, Python retourne une exception et interrompt l’exécution de notre programme de manière instantanée. L’idéal quand une telle exception survient, serait de la traiter, que ce soit en remédiant au problème, si une solution existe afin de corriger ou éviter l’exception et revenir à une exécution normale de notre code, ou encore en terminant proprement notre programme et en informant l’utilisateur du problème qui est survenu.
Pour cela on peut utiliser les block try / except en Python, qui permet d’intercepter les exceptions et de les traiter. Le block try / except à la syntaxe suivante :
try:
# code qui peut lancer une exception
except <Exception> as <nom_de_variable>:
# code à exécuter en cas d'exceptionA noter que le mot clé as suivi d’un « nom_de_variable » est optionnel, mais peut être utile si vous souhaitez logger ou inspecter l’exception qui a été levée par le code.
Dans notre exemple si on souhaite afficher l’exception et redemander son âge à l’utilisateur, on peut faire la chose suivante :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
age = None
while age is None:
try:
age = ask_age()
print(f"Vous avez {age} ans !")
except ValueError as ex:
print(ex)
print("Veuillez entrer un nombre valide !")Si on execute notre programme et qu’on entre tout d’abord un texte invalide, puis un nombre valid, on obtient :

Notre programme ne crash plus et on traite l’exception proprement. Si on ne souhaite pas utiliser l’object contentant l’exception qui a été levé, on peut également faire la chose suivante :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
age = None
while age is None:
try:
age = ask_age()
print(f"Vous avez {age} ans !")
except ValueError:
print("Veuillez entrer un nombre valide !")Ce qui nous donne le résultat :

Attaquons-nous maintenant à un deuxième exemple. Au lieu de demander en boucle son âge à notre utilisateur, nous allons lui demander son âge une fois et si l’utilisateur à plus de 18 ans, on va lui afficher le contenu de notre fichier « input/sample.txt ». Pour cet exemple, nous allons vouloir gérer deux erreurs. Si l’utilisateur entre autre chose qu’un nombre valide en tant qu’âge, on va lui afficher un message d’erreur, si le fichier « input/sample.txt » n’existe pas, on affiche également un message d’erreur.
L’exception levée, lorsqu’on essaye de lire un fichier qui n’existe pas, est l’exception FileNotFoundError et pour pouvoir intercepter cette exception nous pouvons enchaîner le try / except avec un deuxième except :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
def get_file_content():
with open('input/sample.txt', 'r') as file:
return file.read()
try:
age = ask_age()
if age >= 18:
file_content = get_file_content()
print(file_content)
else:
print("Désolé l'accès est interdit aux moins de 18 ans !")
except ValueError:
print("Malheureusement la valeur saisie n'est pas un nombre !")
except FileNotFoundError:
print("Le fichier input/sample.txt n'existe pas !")Comme on peut le voir, on peut ajouter autant d’except que nécessaire afin de traiter chaque exception qui nous intéresse. Notez que si vous voulez traiter plusieurs erreurs de la même façon, Python vous permet d’intercepter plusieurs erreur avec un seul except en lui passant un tuple d’exceptions :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
def get_file_content():
with open('input/sample.txt', 'r') as file:
return file.read()
try:
age = ask_age()
if age >= 18:
file_content = get_file_content()
print(file_content)
else:
print("Désolé l'accès est interdit aux moins de 18 ans !")
except (ValueError, FileNotFoundError):
print("Une erreur est survenue !")Dans cette exemple notre except traite aussi bien la ValueError que la FileNotFoundError en un seul bloque.
Il peut arriver que du code Python lève des erreurs inattendues. Imaginez par exemple que nous n’ayons plus les droits nécessaires pour lire le fichier « input/sample.txt », ou tout autre erreur que n’avions pas prévue lors de l’écriture du code. Python permet d’intercepter ces erreurs en utilisant un except Exception. Ce bloque doit être placé en tant que dernier except et ne dois être utilisé qu’en dernier recours, afin d’éviter que nos programmes ne plantent dans des situations imprévues.
Il est important de comprendre que except Exception ne doit jamais être utilisé pour remplacer les except spécifiques que l’on souhaite traiter explicitement dans notre code.
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
def get_file_content():
with open('input/sample.txt', 'r') as file:
return file.read()
try:
age = ask_age()
if age >= 18:
file_content = get_file_content()
print(file_content)
else:
print("Désolé l'accès est interdit aux moins de 18 ans !")
except ValueError:
print("Malheureusement la valeur saisie n'est pas un nombre !")
except FileNotFoundError:
print("Le fichier input/sample.txt n'existe pas !")
except Exception as ex:
print(f"Une erreur inattendue est survenue : {ex}")except Exception est donc utile pour:
- afficher un message d’erreur générique à l’utilisateur
- logger une erreur avant d’arrêter ou de relancer notre programme
En revanche, except Exception ne doit jamais être utilisé pour :
- ignorer silencieusement des exceptions
- remplacer des except spécifiques
- masquer des erreurs de programmation
Les instructions finally et else
Il existe encore deux instructions très utiles que nous pouvons utiliser avec les blocs try / except.
La première est finally, qui permet de garantir l’exécution d’un bloc de code, indépendamment de ce qui se passe dans le try / except. Que le code s’exécute sans exception, qu’une exception soit interceptée, qu’un return soit exécuté ou même qu’une exception non interceptée soit levée, le code écrit dans le bloc finally sera toujours exécuté.
L’instruction else, quant à elle, permet d’exécuter un bloc de code uniquement si le code contenu dans le try s’est déroulé sans aucune exception.
Mettons tout cela en pratique :
def ask_age():
age_text = input("Quel est votre âge ? ")
return int(age_text)
def get_file_content():
with open('input/sample.txt', 'r') as file:
return file.read()
try:
age = ask_age()
if age >= 18:
file_content = get_file_content()
print(file_content)
else:
print("Désolé l'accès est interdit aux moins de 18 ans !")
except ValueError:
print("Malheureusement la valeur saisie n'est pas un nombre !")
except FileNotFoundError:
print("Le fichier input/sample.txt n'existe pas !")
except Exception as ex:
print(f"Une erreur inattendue est survenue : {ex}")
else:
print("Tout s'est bien passé !")
finally:
print("Merci et à bientôt !")Dans cet exemple, si aucune exception ne survient lors de l’exécution de notre code, le message « Tout s’est bien passé ! » s’affiche. Ensuite, indépendamment du fait que des exceptions aient eu lieu ou non, le bloc finally affiche le message « Merci et à bientôt ! ».
finally est donc une instruction très importante lorsque le code dans notre try / except réserve des ressources qui doivent absolument être libérées avant de retourner un résultat, ou encore lorsqu’il faut garantir l’exécution d’une action critique quoi qu’il arrive.
Attention à l’ordre des différents blocs. Le else doit venir après le dernier except, et le finally vient en toute dernière position.
Créer de nouveaux types d’exceptions
Revenons à notre fonction ask_age(), pour l’instant elle se contente de demander l’âge de l’utilisateur, de le convertir en entier et de le retourner. Idéalement, cette fonction devrait vérifier que l’âge est valable, et si l’âge est trop grand ou trop petit pour être correct, ça aurait été bien de pouvoir générer une exception spécifique à ce problème.
Et bien en Python, pour créer de nouveaux types d’exceptions, il suffit de définir une nouvelle classe qui hérite de la classe Exception, comme ceci :
class InvalidAgeError(Exception):
passEnsuite, on peut lever cette exception en utilisant le mot clé raise suivi de notre nouvelle Exception à laquelle on passe un message d’erreur en paramètre :
def ask_age():
age_text = input("Quel est votre âge ? ")
age = int(age_text)
if age < 0 or age > 150:
raise InvalidAgeError("L'âge doit être compris entre 0 et 150 ans.")
return ageMaintenant nous pouvons intercepter cette exception, comme nous l’avons fait jusqu’à présent avec un except :
class InvalidAgeError(Exception):
pass
def ask_age():
age_text = input("Quel est votre âge ? ")
age = int(age_text)
if age < 0 or age > 150:
raise InvalidAgeError("L'âge doit être compris entre 0 et 150 ans.")
return age
def get_file_content():
with open('input/sample.txt', 'r') as file:
return file.read()
try:
age = ask_age()
if age >= 18:
file_content = get_file_content()
print(file_content)
else:
print("Désolé l'accès est interdit aux moins de 18 ans !")
except ValueError:
print("Malheureusement la valeur saisie n'est pas un nombre !")
except FileNotFoundError:
print("Le fichier input/sample.txt n'existe pas !")
except InvalidAgeError:
print("L'âge entré est invalide !")
except Exception as ex:
print(f"Une erreur inattendue est survenue : {ex}")
else:
print("Tout s'est bien passé !")
finally:
print("Merci et à bientôt !")Et là, si on relance notre programme et si on entre un âge supérieur à 150, on obtient bien notre message d’erreur :

Conclusion
Et voilà, nous venons de voir comment gérer des exceptions en Python. Quelques paragraphs plus haut, on a très vite mentionné la création d’une classe, quand nous avons vu comment créer nos propres exceptions, alors que nous n’avons pas encore abordé le sujet des classes. Justement le prochain chapitre sera une introduction aux classes, ou on verra en détail ce que sont les classes et comment les utiliser.