Bonjour ! Dans la leçon précédente, nous avons vu comment lire et écrire dans des fichiers, une compétence essentielle pour la manipulation de données. Nous avons même eu un petit aperçu de la gestion des erreurs avec try...except pour gérer le cas où un fichier n'existe pas (FileNotFoundError). Cet aperçu a soulevé une question importante : que se passe-t-il lorsque les choses ne se passent pas comme prévu dans un programme ?
Les programmes robustes, en particulier dans le domaine du machine learning où les données peuvent être imprévisibles, ne se contentent pas de fonctionner dans des conditions idéales. Ils anticipent les problèmes et y réagissent de manière contrôlée. C'est l'objectif de cette leçon. Nous allons généraliser le concept que nous avons entrevu pour vous apprendre à gérer les erreurs potentielles avec élégance en utilisant les blocs try/except.
Nous allons explorer la structure complète de la gestion des exceptions en Python, y compris les clauses else et finally, afin que vous puissiez écrire du code qui est non seulement fonctionnel mais aussi résilient et fiable.
1. Erreurs de Syntaxe vs. Exceptions
Avant de plonger dans la gestion des erreurs, il est important de distinguer deux types de problèmes en Python.
- Erreurs de Syntaxe (Syntax Errors) : Ce sont des erreurs dans la "grammaire" de votre code. Python les détecte avant même de commencer à exécuter le programme. Par exemple, une parenthèse manquante ou un mot-clé mal orthographié. Le programme ne peut tout simplement pas démarrer.
- Exceptions : Ce sont des erreurs qui se produisent pendant l'exécution du code. La syntaxe est correcte, mais une opération impossible est tentée. Par exemple, diviser un nombre par zéro ou essayer d'ouvrir un fichier qui n'existe pas. Sans gestion, une exception fait planter le programme.
Python Exceptions: An Introduction
Cet article de Real Python explique clairement cette distinction fondamentale.
Lisez la section intitulée Understanding Exceptions and Syntax Errors. Elle illustre la différence avec un exemple simple.
C'est pour gérer ces exceptions, ces erreurs d'exécution, que nous utilisons le bloc try...except.
2. L'Anatomie d'un Bloc try...except
La philosophie de Python est souvent résumée par l'acronyme EAFP : "Easier to Ask for Forgiveness than Permission" (Il est plus facile de demander pardon que la permission). Au lieu de vérifier à l'avance si une opération est possible, on essaie de la faire et on gère l'erreur si elle se produit.
La structure de base est la suivante :
try:
# Code qui pourrait potentiellement lever une exception
# Par exemple, une conversion de type ou une opération mathématique
resultat = 10 / 0
except ZeroDivisionError:
# Code à exécuter SEULEMENT si l'exception spécifiée se produit
print("Erreur : Vous ne pouvez pas diviser par zéro !")
print("Le programme continue...")
Sans le bloc try...except, le programme planterait à la ligne 10 / 0. Grâce à lui, l'exécution saute au bloc except correspondant, exécute le code qui s'y trouve, puis continue normalement.
Python Tutorial: Using Try/Except Blocks for Error Handling
Cette vidéo de Corey Schafer, un excellent pédagogue, introduit très bien le sujet en partant de l'exemple de la leçon précédente.
Regardez d'abord l'introduction qui explique le besoin d'un bloc try...except en utilisant l'erreur FileNotFoundError. Ensuite, et c'est un point crucial, visionnez le segment sur l'importance de capturer des exceptions spécifiques. Il montre pourquoi un except trop général peut masquer des bugs et rendre le débogage difficile.
Pourquoi être spécifique est-il si important ?
Utiliser un except: sans spécifier le type d'erreur (un "bare except") est une mauvaise pratique. Cela capture toutes les exceptions, y compris celles que vous n'aviez pas prévues, comme des erreurs de frappe dans vos noms de variables (NameError) ou même des interruptions système (KeyboardInterrupt). Vous risquez de masquer de vrais problèmes dans votre code.
La bonne pratique est de toujours spécifier l'exception que vous vous attendez à gérer : except ValueError:, except FileNotFoundError:, etc.
3. La Hiérarchie des Exceptions
Pour comprendre pourquoi on peut être plus ou moins spécifique, il faut savoir que les exceptions en Python sont organisées en une hiérarchie, comme un arbre généalogique.
Lorsque vous attrapez une exception, vous attrapez aussi toutes ses "descendantes". Par exemple, si vous attrapez LookupError, vous attraperez à la fois IndexError et KeyError. C'est pourquoi attraper Exception est si général : presque toutes les erreurs courantes en héritent.
Gérer plusieurs exceptions
Vous pouvez gérer plusieurs types d'erreurs de deux manières :
-
En empilant les blocs
except:user_input = input("Entrez un nombre : ") try: nombre = int(user_input) resultat = 20 / nombre except ValueError: print(f"'{user_input}' n'est pas un nombre valide.") except ZeroDivisionError: print("La division par zéro n'est pas autorisée.") -
En groupant les exceptions dans un tuple :
try: # Code qui pourrait lever soit un TypeError soit un ValueError pass except (TypeError, ValueError) as e: print(f"Erreur de données : {e}")Notez l'utilisation de
as e. Cela vous permet de capturer l'objet exception lui-même, qui contient souvent un message d'erreur descriptif que vous pouvez afficher ou enregistrer.
4. La Structure Complète : else et finally
Le bloc try...except peut être complété par deux clauses optionnelles : else et finally.

-
La clause
else
Le code dans le blocelses'exécute uniquement si aucune exception n'a été levée dans le bloctry. C'est l'endroit idéal pour mettre le code qui doit s'exécuter après une opération réussie. Cela permet de garder le bloctryaussi petit que possible, en y incluant uniquement la ligne qui risque de provoquer une erreur. -
La clause
finally
Le code dans le blocfinallys'exécute toujours, qu'une exception se soit produite ou non, et même si l'exception n'a pas été attrapée. C'est l'endroit parfait pour les opérations de "nettoyage", comme fermer un fichier ou une connexion à une base de données, afin de s'assurer que les ressources sont correctement libérées.
Voici un exemple complet :
try:
f = open('mon_fichier.txt', 'r')
except FileNotFoundError as e:
print(e)
else:
# Cette partie ne s'exécute que si le fichier a été ouvert avec succès
print("Fichier ouvert avec succès. Contenu :")
print(f.read())
finally:
# Cette partie s'exécute toujours, pour s'assurer que le fichier est fermé s'il a été ouvert
# (Note : le `with open(...)` que nous avons vu gère cela automatiquement et de manière plus sûre)
if 'f' in locals() and not f.closed:
f.close()
print("Le fichier a été fermé.")
else:
print("Opération de nettoyage terminée.")
Learn Python in Arabic #091 - Exceptions Handling Try, Except, Else, Finally
Pour une explication complète en arabe de toute la structure, je vous recommande vivement cette vidéo de la chaîne Elzero Web School.
Regardez l'intégralité de la vidéo qui couvre try, except, else, et finally avec des exemples clairs. Cela renforcera votre compréhension de l'ensemble du flux de contrôle.
5. Bonnes Pratiques et Exemples Concrets
Pour maîtriser la gestion des exceptions, il ne suffit pas de connaître la syntaxe. Il faut aussi adopter de bonnes habitudes.
Python Try-Except Tutorial: Best Practices and Real-World ...
Ce guide de DataCamp offre d'excellents conseils et des exemples tirés du monde réel.
Commencez par lire la section sur les bonnes pratiques : Python try-except Best Practices and Common Pitfalls. Concentrez-vous sur les points clés : garder les blocs try courts et ciblés, et éviter de masquer les erreurs. Ensuite, parcourez les exemples concrets dans la section Real-World Examples and Use Cases. Ils montrent comment try-except est utilisé pour la validation des entrées utilisateur et la lecture de fichiers, des tâches très courantes.
6. Exercices Pratiques
Mettons tout cela en pratique !
Exercice 1 : Calculatrice Sécurisée
Écrivez une fonction diviser() qui :
- Demande à l'utilisateur de saisir un numérateur, puis un dénominateur.
- Tente de convertir les deux entrées en nombres flottants (
float). - Tente d'effectuer la division.
- Gère l'exception
ValueErrorsi les entrées ne sont pas des nombres valides. - Gère l'exception
ZeroDivisionErrorsi le dénominateur est zéro. - Affiche le résultat si tout se passe bien.
- Dans tous les cas, affiche le message "Fin de la tentative de division." à la fin.
Exercice 2 : Lecteur de Fichier Robuste
Écrivez un script qui tente de lire un fichier nommé donnees.txt.
- Utilisez la structure complète
try-except-else-finally. - Dans le bloc
try, ouvrez et lisez le fichier. - Dans le bloc
except FileNotFoundError, affichez un message clair indiquant que le fichier est introuvable. - Dans le bloc
else, affichez le contenu du fichier. - Dans le bloc
finally, affichez "Lecture du fichier terminée.".
Testez votre script deux fois : une fois sans créer donnees.txt, et une fois après l'avoir créé avec un peu de texte à l'intérieur.
Solutions
Solution de l'exercice 1 :
def diviser():
try:
num_str = input("Entrez le numérateur : ")
den_str = input("Entrez le dénominateur : ")
num = float(num_str)
den = float(den_str)
resultat = num / den
except ValueError:
print("Erreur : Veuillez entrer des nombres valides.")
except ZeroDivisionError:
print("Erreur : La division par zéro est impossible.")
else:
print(f"Le résultat de la division est : {resultat}")
finally:
print("Fin de la tentative de division.")
# Appel de la fonction
diviser()
Solution de l'exercice 2 :
# Avant d'exécuter, vous pouvez créer ou non un fichier 'donnees.txt' pour tester les deux cas.
try:
with open('donnees.txt', 'r') as f:
contenu = f.read()
except FileNotFoundError:
print("Erreur : Le fichier 'donnees.txt' n'a pas été trouvé.")
else:
print("Contenu du fichier :")
print(contenu)
finally:
print("Lecture du fichier terminée.")
Conclusion
Vous avez fait un grand pas en avant pour devenir un programmeur Python compétent. La gestion des exceptions est ce qui distingue un simple script d'une application robuste et fiable.
Points clés à retenir :
- Utilisez
try...exceptpour gérer les erreurs qui se produisent pendant l'exécution de votre programme. - Soyez toujours spécifique dans vos blocs
exceptpour éviter de masquer des bugs inattendus. - La clause
elses'exécute lorsque le bloctryréussit, idéale pour le code "heureux". - La clause
finallys'exécute toujours, parfaite pour les opérations de nettoyage. - Adoptez la philosophie EAFP ("demander pardon plutôt que permission") pour un code Python plus propre et plus direct.
Dans la prochaine leçon, nous continuerons à enrichir notre boîte à outils Python en apprenant à importer et utiliser des fonctions provenant des modules standards de Python, comme math et random. Cela nous ouvrira la porte à une vaste bibliothèque de fonctionnalités déjà écrites pour nous.