7.1 Création d'exceptions personnalisées
Parfois, les exceptions standard de Python ne satisfont pas entièrement les besoins de votre application. Dans ces cas, vous pouvez créer vos propres exceptions en les héritant de la classe de base Exception ou de toute autre classe d'exceptions appropriée.
Les bases de la création d'exceptions personnalisées
Créer une exception personnalisée implique de définir une nouvelle classe qui hérite de la classe de base Exception. Vous pouvez ajouter vos propres méthodes et attributs à votre classe d'exception pour fournir des informations supplémentaires sur l'erreur.
Exemple de création d'une exception personnalisée simple
Étape 1 : Définition d'une exception personnalisée
class MyCustomError(Exception):
"""Classe pour une exception personnalisée."""
pass
Étape 2 : Utilisation de l'exception personnalisée
def check_value(value):
if value < 0:
raise MyCustomError("La valeur ne doit pas être inférieure à zéro")
try:
check_value(-1)
except MyCustomError as e:
print(f"Une exception personnalisée s'est produite : {e}")
C'est très simple. L'essentiel est que votre exception hérite de la classe Exception ou de l'un de ses descendants.
7.2 Création d'une exception avec des attributs supplémentaires
Vous pouvez ajouter des attributs et des méthodes à votre classe d'exception pour transmettre des informations supplémentaires sur l'erreur survenue.
Exemple :
class NegativeValueError( Exception ):
"""Classe pour une exception personnalisée lors d'une valeur négative."""
def __init__(self, value, message = "La valeur ne doit pas être inférieure à zéro"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Utilisation de l'exception avec des attributs supplémentaires
def check_value(value):
if value < 0:
raise NegativeValueError(value)
try:
check_value(-1)
except NegativeValueError as e:
print(f"Une exception personnalisée s'est produite : {e}")
Notre exception est une classe qui hérite de la classe Exception. Par conséquent, vous pouvez faire avec elle tout ce que vous feriez avec n'importe quelle autre classe : ajouter des champs, des méthodes, des paramètres de constructeur, etc.
Tout pour votre confort, et pour le confort des autres développeurs qui intercepteront vos exceptions.
7.3 Création d'une hiérarchie d'exceptions personnalisées
Pour des applications plus complexes, il est utile de créer des hiérarchies d'exceptions personnalisées. Cela permet de regrouper les exceptions connexes et de simplifier leur gestion.
Exemple :
class ApplicationError(Exception):
"""Classe de base pour toutes les exceptions de l'application."""
pass
class NegativeValueError(ApplicationError):
"""Classe pour une exception personnalisée lors d'une valeur négative."""
def __init__(self, value, message="La valeur ne doit pas être inférieure à zéro"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
class ValueTooLargeError(ApplicationError):
"""Classe pour une exception personnalisée lors d'une valeur trop élevée."""
def __init__(self, value, message="La valeur est trop élevée"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Utilisation de la hiérarchie d'exceptions personnalisées
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Une exception s'est produite : {e}")
except ValueTooLargeError as e:
print(f"Une exception s'est produite : {e}")
except ApplicationError as e:
print(f"Exception générale de l'application : {e}")
7.4 Ordre de capture des exceptions
Lors de la capture des exceptions, en particulier d'une hiérarchie, il est important de les spécifier dans le bon ordre. Bien que le code à l'intérieur des blocs except ne s'exécute jamais simultanément, le point est que la classe de base de l'exception peut capturer les exceptions de toutes ses classes descendant.
Par exemple, le code :
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except ApplicationError as e: # capturera les exceptions de type ApplicationError et tous ses descendants
print(f"Exception générale de l'application : {e}")
Dans le bloc except, les exceptions de type ApplicationError et de toutes ses classes descendants seront capturées.
Et comme toutes les exceptions sont des descendants de la classe Exception, un tel code capturera en fait toutes les exceptions :
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except Exception as e:
print(f"Capture de toutes les exceptions : {e}")
except ApplicationError as e: # Ce code ne sera jamais exécuté
print(f"Exception générale de l'application : {e}")
La capture des exceptions dans le bloc except ApplicationError n'arrivera jamais, car le bloc except Exception capturera en fait toutes les exceptions de type Exception et tous ses descendants.
Solution
C'est pourquoi il est d'usage de capturer les exceptions dans l'ordre inverse de l'héritage : plus une classe est proche de la classe Exception, plus elle est basse.
Exemple :
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Une exception s'est produite : {e}")
except ApplicationError as e:
print(f"Exception générale de l'application : {e}")
except Exception as e:
print(f"Capture de toutes les exceptions : {e}")
Dans cet exemple, les blocs except sont positionnés dans un ordre qui correspond à leur hiérarchie d'héritage : on intercepte d'abord les exceptions plus spécifiques, comme NegativeValueError, puis les plus générales, comme ApplicationError. Cela permet de correctement traiter les exceptions et d'éviter que les gestionnaires plus généraux capturent une exception avant que les blocs except plus spécialisés ne puissent la traiter.
GO TO FULL VERSION