Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 30

Error Handling with Try/Except

Recommended resources

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.

Cette image montre la structure arborescente des exceptions intégrées de Python. `BaseException` est à la racine. Des erreurs spécifiques comme `IndexError` ou `KeyError` sont des sous-types de `LookupError`, qui est lui-même un sous-type de `Exception`.

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 :

  1. 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.")
    
  2. 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.

Ce diagramme illustre le chemin d'exécution. Le code dans `try` est exécuté. Si une exception se produit, le bloc `except` est exécuté. Sinon, c'est le bloc `else` qui est exécuté. Dans tous les cas, le bloc `finally` est exécuté à la fin.
  • La clause else
    Le code dans le bloc else s'exécute uniquement si aucune exception n'a été levée dans le bloc try. 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 bloc try aussi petit que possible, en y incluant uniquement la ligne qui risque de provoquer une erreur.

  • La clause finally
    Le code dans le bloc finally s'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 :

  1. Demande à l'utilisateur de saisir un numérateur, puis un dénominateur.
  2. Tente de convertir les deux entrées en nombres flottants (float).
  3. Tente d'effectuer la division.
  4. Gère l'exception ValueError si les entrées ne sont pas des nombres valides.
  5. Gère l'exception ZeroDivisionError si le dénominateur est zéro.
  6. Affiche le résultat si tout se passe bien.
  7. 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.

  1. Utilisez la structure complète try-except-else-finally.
  2. Dans le bloc try, ouvrez et lisez le fichier.
  3. Dans le bloc except FileNotFoundError, affichez un message clair indiquant que le fichier est introuvable.
  4. Dans le bloc else, affichez le contenu du fichier.
  5. 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...except pour gérer les erreurs qui se produisent pendant l'exécution de votre programme.
  • Soyez toujours spécifique dans vos blocs except pour éviter de masquer des bugs inattendus.
  • La clause else s'exécute lorsque le bloc try réussit, idéale pour le code "heureux".
  • La clause finally s'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.