Exceptions Personnalisées

En Python, les exceptions sont un moyen de réagir aux erreurs pouvant survenir lors de l'exécution d'un programme. Python possède de nombreuses exceptions intégrées telles que IndexError lorsque vous essayez d'accéder à un index qui n'existe pas dans une liste, ou TypeError lorsque vous tentez d'effectuer une opération sur un type qui ne la prend pas en charge. Cependant, il peut parfois être utile de définir nos propres exceptions. Cela nous permet de fournir des messages d'erreur significatifs et de répondre à des situations spécifiques que les exceptions intégrées ne peuvent pas gérer. Les exceptions personnalisées sont créées en définissant une nouvelle classe qui hérite de la classe intégrée Exception ou de l'une de ses sous-classes.
Considérons un programme qui fonctionne avec un système de bibliothèque théorique. Dans ce système, un utilisateur ne doit pas être autorisé à emprunter plus de 5 livres à la fois. Voici comment nous pourrions créer une exception personnalisée pour cela :
class TooManyBooksError(Exception):  # Définir une nouvelle classe d'exception
    pass

def checkout_books(user, num_books):
    if num_books > 5:
        # Lancer une exception si l'utilisateur essaie d'emprunter plus de 5 livres
        raise TooManyBooksError('Vous ne pouvez pas emprunter plus de 5 livres à la fois.')  # Lever notre exception personnalisée
    # Sinon, ajouter les livres au compte de l'utilisateur.
    user.books += num_books
Dans l'exemple ci-dessus, si un utilisateur essaie d'emprunter plus de 5 livres à la fois, notre exception personnalisée TooManyBooksError sera levée avec un message d'erreur spécifique. Si l'exception n'est pas interceptée, le programme arrêtera son exécution et le message d'erreur sera affiché dans la console.
Nous pouvons intercepter cette exception de la même manière que les exceptions intégrées en utilisant un bloc try / except :
try:
    checkout_books(user, 7)     # Essayer d'emprunter 7 livres.
except TooManyBooksError as e:  # Intercepter notre exception personnalisée
    print(e)                    # Afficher le message d'erreur.
Si la ligne checkout_books(user, 7) lève une TooManyBooksError, le programme l'interceptera et affichera notre message d'erreur « Vous ne pouvez pas emprunter plus de 5 livres à la fois. ». De cette façon, nous pouvons gérer l'erreur gracieusement et le programme peut continuer à s'exécuter.
Comme pour toute autre classe, nous pouvons ajouter des méthodes à notre classe d'exception. Par exemple, ajoutons une méthode qui calcule combien de livres l'utilisateur doit retourner pour pouvoir emprunter la quantité désirée :
class TooManyBooksError(Exception):
    def __init__(self, attempted, limit=5, checked_out=0):
        self.attempted = attempted
        self.limit = limit
        self.checked_out = checked_out
        self.message = f'Vous avez essayé d\'emprunter {self.attempted} livres, mais la limite est de {self.limit} livres.'
        super().__init__(self.message)
    
    def books_to_return(self):
        return self.checked_out + self.attempted - self.limit
Nous pouvons utiliser cette méthode après avoir intercepté l'exception :
try:
    checkout_books(user, 7)
except TooManyBooksError as e:
    print(e)                                                   # Vous avez essayé d'emprunter 7 livres, mais la limite est de 5 livres.
    print(f'Vous devez retourner {e.books_to_return()} livres.')  # Vous devez retourner 2 livres.
Ainsi, les exceptions personnalisées peuvent avoir leurs propres attributs et méthodes, ce qui en fait un outil puissant pour gérer les erreurs d'une manière adaptée aux besoins spécifiques de votre programme.
 

Bonnes Pratiques Lors de la Définition d'Exceptions Personnalisées

Lorsque vous créez des exceptions personnalisées, vous serez souvent tenté de définir une classe vide qui hérite de Exception, puis de passer le message d'erreur complet en tant que chaîne de caractères à chaque fois que vous levez l'exception. Bien que cette approche fonctionne, elle peut entraîner du code répétitif et rendre plus difficile la cohérence de vos messages d'erreur.
Au lieu de cela, une meilleure pratique consiste à stocker les données dynamiques dans la classe d'exception. De cette façon, vous pouvez construire le message de l'exception en interne, rendant votre code plus propre et mieux organisé :
👎 Mauvaise pratique – passer le message complet à chaque fois :
class TooManyBooksError(Exception):
    pass

# Vous êtes obligé de passer le message à chaque fois
raise TooManyBooksError('Vous avez essayé d\'emprunter 7 livres, mais la limite est 5 !')

# Ce n'est pas une bonne idée sur le long terme
👍 Une meilleure approche – passer les détails dynamiques dans la classe d'exception :
class TooManyBooksError(Exception):
    def __init__(self, attempted, limit=5):
        self.attempted = attempted
        self.limit = limit
        # Construire le message d'erreur à partir des données
        self.message = f'Vous avez essayé d\'emprunter {self.attempted} livres, mais la limite est {self.limit}.'
        super().__init__(self.message)

# Lors de la levée de l'exception, passez simplement les données pertinentes
raise TooManyBooksError(7)
💡
En laissant la classe d'exception gérer la création du message d'erreur, vous ne vous répétez pas. Si vous avez besoin de changer la formulation ou le format du message, vous n'avez à le faire qu'à un seul endroit—à l'intérieur de la méthode __init__ de votre exception.
 

Défi : Base de Données d'Âges

Dans une ville où tout le monde se connaît, le gouvernement local cherche à mettre en place un système de vérification de l'âge dans les lieux de la ville comme les bars, les clubs et les théâtres. Ils ont besoin d'un programme qui, étant donné un dictionnaire des âges des personnes, accepte un nom et renvoie l'âge de cette personne.
Les entrées sont gérées automatiquement. Vous devez implémenter la fonction find_age(name) qui, étant donné un nom, retournera l'âge de la personne.
Cependant, toutes les personnes ne figurent pas nécessairement dans la base de données de la ville. Si le programme ne peut pas trouver un nom dans la base de données, il doit lever une exception personnalisée appelée NameNotFoundError et imprimer un message d'erreur approprié : {name} not found in the database. Assurez-vous de créer le message à l'intérieur de la classe NameNotFoundError.
Entrée
Sortie
5 Alice - 24 Bob - 32 Charlie - 21 Daisy - 27 Edgar - 30 Edgar
Edgar - 30
5 Alice - 24 Bob - 32 Charlie - 21 Daisy - 27 Edgar - 30 George
NameNotFoundError: George not found in the database.
Remarque : Les noms et les âges sont sensibles à la casse et peuvent contenir des espaces. Le nom saisi doit correspondre exactement au nom dans la base de données.
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in
Sign in to continue