• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 25/11/2024

Gérez les exceptions

Découvrez les exceptions

Quiconque écrit dans n’importe quel langage de programmation depuis un certain temps a déjà rencontré une exception. Une exception est un message du programme qui signale que quelque chose s’est mal passé.

Les exceptions peuvent concerner toutes sortes de choses – vous avez peut-être essayé de diviser par zéro, ou fait une faute de frappe dans un nom de variable et essayé d’accéder à quelque chose qui n’existe pas, ou passé une chaîne à une fonction qui attendait un nombre.

Les exceptions sont déclenchées – ou levées, ou lancées – par un programme. Les exceptions que vous avez pu voir précédemment – comme  NameError,  ZeroDivisionError, ou  IndexError  – sont toutes des exceptions intégrées qui sont lancées par les éléments internes de Python lui-même.

Nous pouvons également lancer des exceptions personnalisées dans nos propres programmes. Pour ce faire, on utilise le mot-cléraise.

def get_half_even_number(number):
    if number % 2 == 0:
        return number / 2
    else:
        message = (
        f"This Function only supports halving even numbers. Received: {number}"
        )
        raise Exception(message)

Dans cet exemple, nous déclenchons une exception avec un message – une chaîne qui s’affiche pour l’utilisateur quand l’exception se produit. Dans ce cas, l’exception donne des informations sur l’erreur en elle-même.

Toutes les exceptions Python sont des objets, ce qui mérite d’être souligné.Exception est la classe de base des exceptions Python, dont tout hérite. Cela signifie que nous pouvons créer nos propres exceptions – ce que nous couvrirons après une note rapide sur la…

Gestion des exceptions

Lorsqu’une exception est déclenchée dans notre code – et qu’elle n’est pas gérée – habituellement, notre programme s’arrête.

Nous pouvons gérer une exception en utilisant untry-except (souvent appelé une instruction try-catch dans d’autres langages).

def increase_percent(initial_value, after_value):
    try:
        return (after_value / initial_value) * 100
    except ZeroDivisionError:
        return 0
    except Exception as error:
        print("Uh oh, unexpected error occurred!")
        raise error

Ici, nous avons une fonction,increase_percent, qui calcule l’augmentation (ou la réduction !) du pourcentage à partir d’une valeur initiale. Notre calcul se trouve dans un bloc  try, ce qui signifie que si une exception se produit, elle sera gérée par nos blocs « except », au lieu de se contenter de planter.

Prenons un exemple. Le problème le plus évident qui pourrait survenir ici serait une erreur de division par zéro. Dans cette fonction, si une  ZeroDivisionError  est lancée, nous l’attrapons et retournons 0 à la place, grâce au premier bloc d’exception. L’exception est officiellement gérée et le programme ne plante pas !

D’autre part, si l’exception qui se produit n’est pas une  ZeroDivisionError, nous la déclenchons simplement à nouveau. Vous voyez le  as error  dans le deuxième bloc except ? Il assigne l’objet exception à la variable error, que nous pouvons alors redéclencher – soit pour qu’elle soit gérée par un autre bloc try dans lequel cette fonction a été appelée, soit simplement pour mettre fin au programme.

Lorsqu’une exception est levée, elle se propage dans le programme. Python ne fait plus les choses dans l’ordre, mais lance plutôt continuellement l’exception en remontant la pile – c’est-à-dire la pile de fonctions/méthodes qui ont appelé d’autres fonctions/méthodes. L’exception va continuer à remonter jusqu’à ce qu’elle soit gérée ou qu’elle n’ait plus nulle part où aller. Dans ce dernier cas, le programme plante.

Écrivez des exceptions personnalisées

Dans un programme complexe, de nombreuses choses peuvent mal se passer. Pour gérer des problèmes uniques, Python nous permet de définir nos propres exceptions personnalisées. Si nous gardons en tête que les exceptions sont des objets, nous pouvons définir nos propres classes d’Exceptions, exactement comme nous le ferions pour tout autre objet.

class InvalidAddressException(Exception):
    """Gère les exceptions liées aux mauvaises adresses."""
    pass

 
class OwlContactSystem(ContactSystem):
    def __init__(self, address):
        if (not validate_address(address)):
            raise InvalidAddressException(f"Adresse invalide: {address}"
        self.address = address

Ici, nous utilisons notre  OwlContactSystem  de tout à l’heure. Dans notre constructeur, nous appelons la fonction  validate_address  avec la chaîne d’adresse e-mail qui est donnée. Si la validation de l’adresse e-mail échoue, nous déclenchons une  InvalidAddressException   – qui aura probablement besoin d’être gérée par quiconque appelle ce constructeur.

Mais  InvalidAddressException  ne fait rien, alors pourquoi l’utiliser ?

De nombreuses exceptions personnalisées ressemblent à cela. Bien qu’il soit possible de surcharger des méthodes dans une exception personnalisée, le simple fait de disposer d’un type séparé nous est en réalité très utile.

Nous pouvons aussi mettre un message par défaut, ce qui est souvent plus pratique :

class InvalidAddressException(Exception):
    """Gère les exceptions liées aux mauvaises adresses."""
 
    def __init__(self, address, base_message="Adresse invalide !", *args, **kwargs):
        """Initialise le message.
         
        
        L’utilisation de *args et **kwags permet de prendre un nombre
        de paramètres dynamiques.
        """
        msg = f"{base_message} Adresse: {address}"
        super().__init__(msg, *args, **kwargs)

Souvenez-vous de l’instruction except –  except InvalidAddressException, par exemple. Le bloc  except  correspond au type de l’exception. Autrement dit, le bloc  except  aura lieu si l’expression déclenchée est du typeInvalidAddressException. Le type de l’exception est suffisant à lui seul !

Une dernière chose : les exceptions personnalisées dans une grosse application n’héritent habituellement pas directement d’exception. Nous faisons alors généralement quelque chose qui ressemble à ceci :

class MyAppException(Exception):
    pass


class MyAppInvalidAddressException(MyAppException):
    pass

Nous définissons  MyAppException  comme classe de base pour notre hiérarchie d’exceptions personnalisées. Cela nous permet de savoir très rapidement si une exception est déclenchée depuis notre application ou pas ! Vous verrez que de nombreuses bibliothèques Python ont également leur propre classe de base d’exceptions personnalisées.

Voyons un exemple de comment utiliser les exceptions, dans ce screencast :

À vous de jouer : créez des exceptions personnalisées

À vous de jouer

Étant donné la classe Utilisateur suivante et son constructeur, créez deux exceptions personnalisées partageant une même classe parent. Ces exceptions personnalisées devront indiquer un nom d’utilisateur trop court ou un mot de passe insuffisant.

Une fois que vous avez vos exceptions personnalisées, modifiez le constructeur ci-dessous pour vérifier que les noms d’utilisateurs comprennent au moins trois caractères, et que les mots de passe contiennent au moins une lettre et un chiffre. Levez l’exception adaptée en cas de problème.

Ensuite, essayez de créer un Utilisateur avec différents noms d’utilisateur et mots de passe, pour tester si cela fonctionne.

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

En résumé

  • Une exception est déclenchée (ou lancée) avec  raise  quand un problème apparaît dans un programme.

  • On peut gérer les exceptions en utilisant des blocs try.

  • Les exceptions ne sont que des objets, ce qui signifie que nous pouvons définir nos propres exceptions personnalisées !

… et c’est fini ! Mais avant de partir, testez vos connaissances avec notre quiz de troisième partie.

Exemple de certificat de réussite
Exemple de certificat de réussite