Gestion des exceptions
Comme d'autres langages, Python fournit un mécanisme de gestion d'exceptions via les blocs try / except. Une exception est un événement qui survient pendant l'exécution et interrompt le flux normal du programme.
| Type d'erreur | Description | Détectée quand ? | Exemple |
|---|---|---|---|
| Erreur de syntaxe | L'analyseur Python ne comprend pas la ligne | Avant l'exécution | if x = 5: |
| Exception | Erreur survenant pendant l'exécution | À l'exécution | 1 / 0 |
Exceptions standard les plus fréquentes
| Exception | Cause | Exemple déclencheur |
|---|---|---|
ZeroDivisionError | Division par zéro | 5 // 0 |
TypeError | Type d'argument incorrect | "2" + 2 |
ValueError | Valeur incorrecte pour le type | int("abc") |
IndexError | Indice hors limites | [1,2][5] |
KeyError | Clé absente dans un dictionnaire | d["x"] si "x" absent |
AttributeError | Attribut ou méthode inexistant | obj.inconnu |
ImportError | Module introuvable | import inexistant |
FileNotFoundError | Fichier introuvable | open("x.txt") |
RecursionError | Profondeur de récursion dépassée | Récursion infinie |
MemoryError | Mémoire insuffisante | Allocation trop grande |
Bloc try / except
try:
# code susceptible de lever une exception
except TypeException1:
# gestion de TypeException1
except (TypeException2, TypeException3):
# gestion de plusieurs exceptions à la fois
except Exception as e:
# gestion générique — e contient le message d'erreur
else:
# exécuté UNIQUEMENT si aucune exception n'a été levée
finally:
# exécuté TOUJOURS, exception ou non- Le bloc
tryest exécuté en premier. - Si aucune exception ne survient → le bloc
exceptest ignoré. - Si une exception survient → le reste du bloc
tryest ignoré, Python cherche leexceptcorrespondant. - Si aucun
exceptne correspond → l'exception est propagée aux blocstryextérieurs. - Si elle n'est jamais gérée → le programme s'arrête avec un traceback.
Exemple — Division avec gestion d'exception
def division(a, b):
try:
resultat = a // b
print(f"{a} // {b} = {resultat}")
except ZeroDivisionError:
print("Erreur : division par zéro !")
print("Première instruction")
division(4, 2)
print("Deuxième instruction")
division(4, 0)Première instruction 4 // 2 = 2 Deuxième instruction Erreur : division par zéro !
Exemple — Plusieurs clauses except
Une instruction try peut avoir plusieurs clauses except pour gérer différentes exceptions. Au plus un gestionnaire sera exécuté par exception.
def convertir(valeur):
try:
nombre = int(valeur)
resultat = 100 // nombre
print(f"100 // {nombre} = {resultat}")
except ZeroDivisionError:
print("Erreur : division par zéro !")
except ValueError:
print(f"Erreur : '{valeur}' n'est pas un entier valide.")
except TypeError:
print("Erreur : type incorrect.")
convertir("5") # OK
convertir("0") # ZeroDivisionError
convertir("abc") # ValueError
convertir(None) # TypeError100 // 5 = 20 Erreur : division par zéro ! Erreur : 'abc' n'est pas un entier valide. Erreur : type incorrect.
Clauses else et finally
Clause else
Le bloc else est exécuté uniquement si aucune exception n'a été levée dans le bloc try. Il permet de séparer le code "normal" du code de gestion d'erreur.
Exemple — try / except / else
def division(a, b):
try:
resultat = a // b
except ZeroDivisionError:
print("Erreur : division par zéro !")
else:
print(f"Résultat : {resultat}") # seulement si pas d'exception
division(10, 2) # Résultat : 5
division(10, 0) # Erreur : division par zéro !Résultat : 5 Erreur : division par zéro !
Clause finally
Le bloc finally est toujours exécuté, qu'une exception ait été levée ou non. Il est typiquement utilisé pour libérer des ressources (fermer un fichier, une connexion, etc.).
Exemple — try / except / finally
def lire_fichier(chemin):
fichier = None
try:
fichier = open(chemin, 'r')
contenu = fichier.read()
print(contenu)
except FileNotFoundError:
print(f"Fichier '{chemin}' introuvable.")
finally:
if fichier:
fichier.close()
print("Fichier fermé.") # exécuté dans tous les cas
lire_fichier("data.txt")with Pour la gestion de ressources (fichiers, connexions), le gestionnaire de contexte with est plus élégant que finally: il garantit la fermeture automatique même en cas d'exception.with open("data.txt", "r") as f:
contenu = f.read() # f.close() est appelé automatiquement| Clause | Exécutée quand ? | Usage typique |
|---|---|---|
try | Toujours en premier | Code susceptible de lever une exception |
except | Si une exception correspond | Gestion de l'erreur |
else | Si aucune exception | Code "succès" isolé du try |
finally | Toujours | Libération de ressources |
Lever une exception — raise
L'instruction raise permet de forcer manuellement une exception. Elle est utile pour valider des données ou signaler explicitement une condition d'erreur.
raise TypeException("message d'erreur") # lever avec message
raise # re-lever l'exception couranteExemple — Lever et capturer une exception
def division(a, b):
try:
if b == 0:
raise ZeroDivisionError("Division par zéro interdite !")
return a // b
except ZeroDivisionError as e:
print(f"Erreur interceptée : {e}")
raise # re-propage l'exception vers l'appelant
try:
division(4, 0)
except ZeroDivisionError:
print("Erreur confirmée dans le bloc appelant.")Erreur interceptée : Division par zéro interdite ! Erreur confirmée dans le bloc appelant.
Exemple — Validation de données avec raise
def set_age(age):
if not isinstance(age, int):
raise TypeError(f"L'âge doit être un entier, reçu : {type(age).__name__}")
if age < 0 or age > 150:
raise ValueError(f"Âge invalide : {age}. Attendu entre 0 et 150.")
print(f"Âge défini : {age}")
set_age(25) # OK
set_age(-5) # ValueError
set_age("vingt") # TypeErrorÂge défini : 25 ValueError: Âge invalide : -5. Attendu entre 0 et 150. TypeError: L'âge doit être un entier, reçu : str
Intercepter toutes les exceptions
On peut utiliser la classe de base Exception pour capturer n'importe quelle exception et accéder à son message via as e.
try:
# code
except Exception as e:
print(type(e).__name__, ":", e) # nom + message de l'erreurExemple
def tester(valeur):
try:
resultat = 100 // int(valeur)
print(f"Résultat : {resultat}")
except Exception as e:
print(f"[{type(e).__name__}] {e}")
tester("5") # OK
tester("0") # ZeroDivisionError
tester("abc") # ValueErrorRésultat : 20 [ZeroDivisionError] integer division or modulo by zero [ValueError] invalid literal for int() with base 10: 'abc'
except trop large Capturer toutes les exceptions avec except Exception (ou pire, un except nu) peut masquer des erreurs de programmation. Préférez toujours cibler des exceptions spécifiques et réserver except Exception pour la journalisation ou les interfaces utilisateur.Classes d'exceptions de base
Python organise ses exceptions dans une hiérarchie de classes. Connaître cette hiérarchie permet de choisir le bon niveau de capture.
| Classe de base | Sous-exceptions | Description |
|---|---|---|
ArithmeticError | ZeroDivisionError, OverflowError, FloatingPointError | Erreurs arithmétiques |
LookupError | IndexError, KeyError | Clé ou indice invalide |
OSError | FileNotFoundError, PermissionError, IOError | Erreurs liées au système d'exploitation |
ValueError | UnicodeError | Valeur incorrecte pour le type attendu |
RuntimeError | RecursionError, NotImplementedError | Erreurs générales d'exécution |
ArithmeticError
Classe de base pour les erreurs arithmétiques : OverflowError, ZeroDivisionError, FloatingPointError.
def division(a, b):
try:
return a // b
except ArithmeticError as e:
print(f"[ArithmeticError] {e}")
division(10, 0) # capturé par ArithmeticError[ArithmeticError] integer division or modulo by zero
LookupError
Classe de base pour IndexError et KeyError.
T = [1, 2, 3]
d = {"a": 1}
try:
print(T[10])
except LookupError as e:
print(f"[LookupError] {type(e).__name__} : {e}")
try:
print(d["z"])
except LookupError as e:
print(f"[LookupError] {type(e).__name__} : {e}")[LookupError] IndexError : list index out of range [LookupError] KeyError : 'z'
AssertionError
Levée quand une instruction assert échoue. Utile pour les tests et la validation d'invariants.
def diviser_positif(a, b):
assert b > 0, f"b doit être positif, reçu : {b}"
return a / b
try:
diviser_positif(10, -3)
except AssertionError as e:
print(f"[AssertionError] {e}")[AssertionError] b doit être positif, reçu : -3
RecursionError
Levée quand la profondeur de récursion maximale est dépassée (par défaut 1000 en Python).
def infini(n):
return infini(n - 1) # pas de condition d'arrêt
try:
infini(10)
except RecursionError as e:
print(f"[RecursionError] {e}")[RecursionError] maximum recursion depth exceeded
Créer ses propres exceptions
On peut définir des exceptions personnalisées en héritant de la classe Exception. C'est une bonne pratique pour les bibliothèques et les applications complexes.
Exemple — Exception métier personnalisée
class NoteInvalideError(Exception):
"""Exception levée quand une note est hors de [0, 20]."""
def __init__(self, note):
self.note = note
super().__init__(f"Note invalide : {note}. Doit être entre 0 et 20.")
def valider_note(note):
if not (0 <= note <= 20):
raise NoteInvalideError(note)
print(f"Note valide : {note}")
try:
valider_note(15)
valider_note(25)
except NoteInvalideError as e:
print(f"[Erreur] {e}")Note valide : 15 [Erreur] Note invalide : 25. Doit être entre 0 et 20.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.