Exceptions en Python
Gestion des exceptions en Python
Section titled “Gestion des exceptions en Python”Les erreurs sont inévitables en programmation. Python offre des mécanismes robustes pour gérer les erreurs d’exécution (runtime errors) avec élégance, évitant ainsi que votre programme ne plante de manière inattendue.
- Gestion des exceptions (Exception Handling) : Utilisation des blocs
try,except,elseetfinallypour gérer les erreurs au fur et à mesure qu’elles se produisent. - Assertions : Utilisation de l’instruction
assertpour des auto-vérifications internes pendant le développement et le débogage.
Qu’est-ce qu’une exception ?
Section titled “Qu’est-ce qu’une exception ?”Une exception (exception) est un événement qui se produit pendant l’exécution d’un programme et qui perturbe le déroulement normal des instructions. Lorsque Python rencontre une condition d’erreur (comme une division par zéro ou une tentative d’accès à un fichier inexistant), il crée un objet exception.
Si cet objet exception n’est pas ‘capturé’ et géré par votre code, le programme se termine et affiche une traceback (un message d’erreur indiquant où l’erreur s’est produite).
Exceptions intégrées courantes
Section titled “Exceptions intégrées courantes”Python dispose de nombreuses exceptions intégrées pour les erreurs courantes. Les comprendre aide à écrire des blocs except spécifiques. Voici quelques exemples :
| Nom de l’exception | Description |
|---|---|
Exception | La classe de base pour la plupart des exceptions intégrées qui ne provoquent pas l’arrêt du système. |
AttributeError | Levée lorsqu’une référence ou une affectation d’attribut échoue (par exemple, mylist.methode_non_existante()). |
ImportError | Levée lorsqu’une instruction import ne parvient pas à trouver le module ou un nom dans le module. |
ModuleNotFoundError | Sous-classe d’ImportError, levée lorsqu’un module ne peut pas être localisé. |
IndexError | Levée lorsqu’un indice de séquence (index) est hors de portée (par exemple, mylist[10] alors que la liste n’a que 3 éléments). |
KeyError | Levée lorsqu’une clé de dictionnaire n’est pas trouvée (par exemple, mydict['cle_non_existante']). |
NameError | Levée lorsqu’un nom local ou global (variable, fonction) n’est pas trouvé. |
TypeError | Levée lorsqu’une opération ou une fonction est appliquée à un objet de type inapproprié (par exemple, '2' + 2). |
ValueError | Levée lorsqu’une opération ou une fonction reçoit un argument du bon type mais d’une valeur inappropriée (par exemple, int('abc')). |
ZeroDivisionError | Levée lorsque le deuxième argument d’une opération de division ou de modulo est zéro. |
FileNotFoundError | Sous-classe d’OSError, levée lors d’une tentative d’ouverture d’un fichier qui n’existe pas. |
OSError | Classe de base pour les erreurs liées au système d’exploitation (comme fichier non trouvé, permission refusée). |
KeyboardInterrupt | Levée lorsque l’utilisateur appuie sur la touche d’interruption (généralement Ctrl+C). |
Gestion des exceptions : try et except
Section titled “Gestion des exceptions : try et except”Pour gérer les erreurs potentielles, vous placez le code susceptible de lever une exception à l’intérieur d’un bloc try. Vous le faites ensuite suivre d’un ou plusieurs blocs except pour spécifier comment gérer les différents types d’exceptions.
Syntaxe
Section titled “Syntaxe”try: # Code susceptible de lever une exception # ... opérations ... result = 10 / risky_variable file = open("maybe_missing.txt", "r") # ... plus d'opérations ...except ZeroDivisionError: # Gérer spécifiquement la division par zéro print("Erreur : Impossible de diviser par zéro !") result = 0except FileNotFoundError: # Gérer spécifiquement le fichier manquant print("Erreur : Fichier non trouvé !") # Peut-être fournir une valeur par défaut ou quitterexcept Exception as e: # Capturer toute autre exception qui hérite d'Exception print(f"Une erreur inattendue s'est produite : {e}") # Journaliser l'erreur, fournir un message générique, etc.
# Le code ici continue l'exécution si une exception a été capturéePoints clés :
- Python essaie d’exécuter le code dans le bloc
try. - Si une exception se produit, Python arrête l’exécution du bloc
tryet recherche un blocexceptcorrespondant. - Il vérifie les blocs
exceptdans l’ordre. Le premier dont le type correspond à l’exception levée (ou qui est une classe de base de celle-ci) est exécuté. - Si un bloc
exceptcorrespondant est trouvé et exécuté, le programme continue après la structuretry...except(sauf si le blocexceptlui-même lève une exception ou quitte). - Si aucun bloc
exceptcorrespondant n’est trouvé, l’exception se propage vers le haut de la pile d’appels (call stack). Si elle n’est pas capturée, le programme se termine. - Utiliser un type d’exception spécifique (
ZeroDivisionError) est généralement préférable à un type général (Exception) car cela permet une gestion des erreurs adaptée et évite de capturer accidentellement des erreurs non liées. - La clause
as ecapture l’objet exception dans la variablee, permettant d’accéder aux détails de l’erreur.
La clause else
Section titled “La clause else”Vous pouvez ajouter un bloc else facultatif après tous les blocs except. Le code du bloc else s’exécute uniquement si le bloc try se termine sans lever d’exceptions.
Syntaxe
Section titled “Syntaxe”try: # Opérations qui pourraient échouer value = int(input("Enter a number: ")) result = 100 / valueexcept ValueError: print("Invalid input. Please enter a number.")except ZeroDivisionError: print("Cannot divide by zero.")else: # S'exécute uniquement si le bloc try réussit print(f"Result is: {result}") print("Operation successful.")
print("Program continues...")Le bloc else est utile pour le code qui ne doit s’exécuter que lorsque le bloc try a réussi, le séparant du code potentiellement risqué.
La clause finally
Section titled “La clause finally”Un bloc finally facultatif peut être ajouté. Le code du bloc finally s’exécute toujours, qu’une exception se soit produite dans le bloc try ou qu’elle ait été gérée par un bloc except. Il s’exécute même si le bloc try ou except utilise return, break ou continue.
Syntaxe
Section titled “Syntaxe”file = None # Initialiser la variable de fichier en dehors du bloc trytry: print("Attempting to open file...") file = open("my_data.txt", "w") file.write("Writing important data!") # Simuler une erreur pouvant survenir après l'ouverture # result = 10 / 0except FileNotFoundError: print("Error: Could not find the file path to write.")except Exception as e: print(f"An error occurred during writing: {e}")finally: # Ce bloc s'exécute toujours pour le nettoyage print("Entering finally block...") if file and not file.closed: print("Fermeture du fichier.") file.close() else: print("Le fichier n'a pas été ouvert ou est déjà fermé.")
print("Program finished.")Le bloc finally est typiquement utilisé pour des actions de nettoyage, comme la fermeture de fichiers ou de connexions réseau, garantissant que les ressources sont correctement libérées.
Note : Un bloc try doit avoir au moins une clause except ou finally. Il peut avoir des clauses except, une clause finally, ou les deux. Si les deux sont présentes, la clause finally s’exécute en dernier.
Argument d’une exception
Section titled “Argument d’une exception”Comme vu dans les exemples avec except Exception as e:, vous pouvez capturer l’objet exception lui-même. Cet objet contient souvent des informations utiles sur l’erreur.
Exemple :
Section titled “Exemple :”try: x = int('not_a_number')except ValueError as ve: print(f"ValueError capturée !") print(f"Détails de l'erreur : {ve}") # Affiche le message d'erreur standard associé à l'exception print(f"Arguments : {ve.args}") # Les exceptions stockent des arguments, incluant souvent le messageCeci produit une sortie similaire à :
Caught a ValueError!Error details: invalid literal for int() with base 10: 'not_a_number'Arguments: ("invalid literal for int() with base 10: 'not_a_number'",)Lever des exceptions
Section titled “Lever des exceptions”Vous pouvez également lever délibérément des exceptions dans votre propre code à l’aide de l’instruction raise. Ceci est utile lorsque vous détectez une condition d’erreur qui empêche votre fonction ou méthode de remplir son contrat.
Syntaxe
Section titled “Syntaxe”raise ExceptionType("Optional descriptive message about the error")Exemple
Section titled “Exemple”def check_positive(number): if number <= 0: # Lever une exception spécifique et appropriée raise ValueError("Input must be a positive number.") print(f"{number} is positive.")
try: check_positive(10) check_positive(-5)except ValueError as e: print(f"Error caught: {e}")La meilleure pratique est de lever des exceptions intégrées spécifiques (comme ValueError, TypeError) lorsque cela est approprié, ou de créer des exceptions personnalisées pour les erreurs spécifiques à l’application.
Note : Lever des exceptions en utilisant des chaînes de caractères (raise "Niveau invalide !") est obsolète et ne doit pas être utilisé dans le Python moderne.
Exceptions définies par l’utilisateur
Section titled “Exceptions définies par l’utilisateur”Pour les erreurs spécifiques à votre application ou bibliothèque, vous pouvez créer des classes d’exception personnalisées en héritant de Exception ou d’une classe d’exception intégrée plus spécifique.
Exemple
Section titled “Exemple”# Définir une classe d'exception personnaliséeclass InsufficientFundsError(Exception): """Exception personnalisée pour les cas où un compte a des fonds insuffisants.""" def __init__(self, balance, required): self.balance = balance self.required = required message = f"Attempted to withdraw {required}, but only {balance} available." super().__init__(message) # Appeler le constructeur de la classe de base
# Exemple d'utilisationaccount_balance = 100withdrawal_amount = 150
try: if withdrawal_amount > account_balance: raise InsufficientFundsError(account_balance, withdrawal_amount) else: print("Withdrawal successful.") # account_balance -= withdrawal_amountexcept InsufficientFundsError as e: print(f"Transaction Failed: {e}") # Accéder aux attributs personnalisés si nécessaire : # print(f"Current Balance: {e.balance}, Amount Required: {e.required}")Les exceptions personnalisées rendent votre gestion des erreurs plus spécifique et informative.
Assertions en Python
Section titled “Assertions en Python”Une assertion (assertion) est une aide au débogage qui teste une condition. Si la condition est True, rien ne se passe. Si la condition est False, l’instruction assert lève une exception AssertionError avec un message facultatif.
Les assertions sont principalement utilisées pour vérifier les erreurs internes ou les violations d’hypothèses (erreurs de programmeur), et non pour les conditions d’erreur attendues (comme une entrée utilisateur invalide ou des fichiers manquants, qui devraient être gérées par try...except).
Syntaxe
Section titled “Syntaxe”assert condition, "Optional message if condition is False"Exemple
Section titled “Exemple”def calculate_discount(price, discount_percentage): # Vérification des préconditions : s'assurer que les entrées sont valides pour la logique assert price >= 0, "Price cannot be negative" assert 0 <= discount_percentage <= 100, "Discount must be between 0 and 100"
discount_amount = price * (discount_percentage / 100) final_price = price - discount_amount
# Vérification post-condition : s'assurer que le résultat est logique assert 0 <= final_price <= price, "Final price calculation seems wrong" return final_price
# Appel valideprint(f"Discounted price: {calculate_discount(100, 10)}")
# Appel invalide - lèvera une AssertionErrortry: print(calculate_discount(100, 110))except AssertionError as e: print(f"Assertion Failed: {e}")Note importante : Les assertions peuvent être désactivées globalement en Python en exécutant l’interpréteur avec l’option -O (optimiser) (python -O votre_script.py). Par conséquent, elles ne doivent pas être utilisées pour la logique de gestion des erreurs qui doit toujours être présente.