Gérer les exceptions

Qu’est-ce donc ?

Une exception est levée quand une erreur est commise

[1]:
nexistepas
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[1], line 1
----> 1 nexistepas

NameError: name 'nexistepas' is not defined
[2]:
2 / 0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[2], line 1
----> 1 2 / 0

ZeroDivisionError: division by zero
[3]:
'un' + 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 'un' + 2

TypeError: can only concatenate str (not "int") to str
[4]:
'bonjour'[9]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[4], line 1
----> 1 'bonjour'[9]

IndexError: string index out of range
[5]:
{'un': 1}['deux']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[5], line 1
----> 1 {'un': 1}['deux']

KeyError: 'deux'

Le Traceback permet de suivre l’imbrication des appels au moment de l’erreur

[6]:
def f0(x):
    return x / 0

def f1(x):
    return f0(x) / 1

def f2(x):
    return f1(x) / 2

def f3(x):
    return f2(x) / 3

f3(1)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[6], line 13
     10 def f3(x):
     11     return f2(x) / 3
---> 13 f3(1)

Cell In[6], line 11, in f3(x)
     10 def f3(x):
---> 11     return f2(x) / 3

Cell In[6], line 8, in f2(x)
      7 def f2(x):
----> 8     return f1(x) / 2

Cell In[6], line 5, in f1(x)
      4 def f1(x):
----> 5     return f0(x) / 1

Cell In[6], line 2, in f0(x)
      1 def f0(x):
----> 2     return x / 0

ZeroDivisionError: division by zero

Il est possible d’émettre soit même une exception pour signaler une erreur.

[7]:
def fonction_qui_n_aime_pas_toto(valeur):
    """ affiche valeur
    Je n'aime pas Toto, donc 'toto' est une valeur interdite !
    """
    if valeur == 'toto':
        raise ValueError("T'es pas beau, toto !")  # pensez à mettre un message utile...
    print(valeur)
[8]:
fonction_qui_n_aime_pas_toto('tata')
tata
[9]:
fonction_qui_n_aime_pas_toto('toto')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 1
----> 1 fonction_qui_n_aime_pas_toto('toto')

Cell In[7], line 6, in fonction_qui_n_aime_pas_toto(valeur)
      2 """ affiche valeur
      3 Je n'aime pas Toto, donc 'toto' est une valeur interdite !
      4 """
      5 if valeur == 'toto':
----> 6     raise ValueError("T'es pas beau, toto !")  # pensez à mettre un message utile...
      7 print(valeur)

ValueError: T'es pas beau, toto !

De nombreuses exceptions sont définies de base

https://docs.python.org/2/library/exceptions.html#exception-hierarchy

try / except / else /finally

Il est possible de “sécuriser” une portion de code. Voire même d’intégrer l’erreur dans la logique du code.

try:
    # bloc d'instruction dont on veux contrôler les exceptions émises
except ExceptionType1 as err1:
    # Traitement de err1
    # Typiquement:
    #    - on a une solution de repli dans le cas de err1
    #    OU
    #    - on sauve les meubles et on fait rebondir err1 (ou une nouvelle erreur)
except ExceptionType2 as err2:
    # Traitement de err2
    # ...
except ExceptionType3 as err3:
    # Traitement de err3
    # ...
else:
    # Si aucune exception n'est émise dans le try
    # alors ce bloc est exécuté
finally:
    # Ce bloc sera exécuté quoi qu'il arrive

Exercices

Ecrire une fonction get(obj, index, default) avec le même comportement que dict.get() mais qui marche aussi bien pour les dict ou les listes .

Ecrire une fonction map_with_default(function, sequence, default) qui marche comme map(function, sequence) sauf que si une erreur est produite par function lors de son évaluation, l’erreur n’est pas propagée. A la place, la valeur manquante est assignée à default.