# Les exceptions et leurs gestion

## Introduction

Quelles sont les erreurs possibles dans le code suivant ?

```python
nombre = int(input("Entrez un nombre:"))
resultat = 10 / nombre
```

Si on entre :&#x20;

* Une chaine de caractères (autre que des nombres), alors nous aurons l’erreur suivante :&#x20;

<figure><img src="https://700524925-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn5YnWU89G98lz0ROIcGu%2Fuploads%2F4iVOJfPWgNg9vboDqnWH%2Fimage.png?alt=media&#x26;token=1c27b690-6176-4ce4-8db5-ccd563dafcd7" alt=""><figcaption></figcaption></figure>

* Si nous entrons le chiffre 0, alors nous aurons l’erreur suivante :&#x20;

<figure><img src="https://700524925-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn5YnWU89G98lz0ROIcGu%2Fuploads%2FAJlSFIt5CnzmfFcdeM2J%2Fimage.png?alt=media&#x26;token=4d48851d-9e60-4cf2-be62-67ace8583aaf" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}

* <mark style="background-color:red;">1</mark> : le chemin (incluant le nom) du fichier dans lequel se trouve l'erreur.
* <mark style="background-color:red;">2</mark> : le numéro de la ligne de code où se trouve l'erreur. <mark style="color:red;">La cause peut provenir d'une ligne précédente (comme dans l'exemple suivant).</mark>&#x20;
* <mark style="background-color:red;">3</mark> : La ligne de code où se trouve l'erreur.
* <mark style="background-color:red;">4</mark> : Le **type de l'exception** et une brève description de l'erreur. Ici, les types d'exceptions dans les deux exemples sont **`ValueError`**&#x65;t **`ZeroDivisionError`**.
  {% endhint %}

Pour éviter ces erreurs d’exécution, nous pouvons, dans certains cas, valider la valeur entrée à l’aide d’un `if` avant l’instruction dans laquelle il risque d’y avoir une erreur, ou d’utiliser la syntaxe *`try … except`*.

## Les exceptions

Les erreurs détectées durant l'exécution sont appelées des *exceptions*. Dans les exemples d'erreurs précédents, les types d'exceptions sont **`ValueError`**&#x65;t **`ZeroDivisionError`** (voir point rouge <mark style="background-color:red;">4</mark> dans les images précédentes).\
Autres exemples :

* **`TypeError`**

<figure><img src="https://700524925-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn5YnWU89G98lz0ROIcGu%2Fuploads%2FOzAk7NxRqQjgz4GAyxG7%2Fimage.png?alt=media&#x26;token=8bb9fc40-2782-4ddf-a7ad-50ade0b76896" alt=""><figcaption></figcaption></figure>

**Signification du message d'erreur :** On ne peut pas concaténer une chaîne de caractères (str) et un entier (int).

* **`NameError`**

<figure><img src="https://700524925-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn5YnWU89G98lz0ROIcGu%2Fuploads%2FWIEK0waWEMHiADjvVhfw%2Fimage.png?alt=media&#x26;token=813a751c-28ee-4eff-942c-b4ef2adc7dbe" alt=""><figcaption></figcaption></figure>

**Signification du message d'erreur :** la variable x n'est pas définie.

* ~~**`IndexError`**~~

<figure><img src="https://700524925-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fn5YnWU89G98lz0ROIcGu%2Fuploads%2F1vFKQVyKwrnUNd54QlJy%2Fimage.png?alt=media&#x26;token=5c4dba85-dc93-48a8-9fcf-7f078127807a" alt="" width="188"><figcaption></figcaption></figure>

~~**Signification du message d'erreur :** le numéro de l'indice déborde (l'élément à l'indice 6 n'existe pas dans la liste).~~

Pour tous les types d'exceptions, voir la documentation officielle de python suivante :&#x20;

{% embed url="<https://docs.python.org/fr/3/library/exceptions.html#concrete-exceptions>" %}

Documentation complète sur les exceptions :&#x20;

{% embed url="<https://docs.python.org/fr/3/tutorial/errors.html>" %}

## Gestion des exceptions

### Syntaxe try/except

<pre class="language-python"><code class="lang-python"><strong>try:
</strong>    # Instruction(s) contenant potentiellement une exception.
except &#x3C;Type de l'exception>:
    # Instructions de gestion de l'exception.
</code></pre>

* Dans le bloc « **`try`** », on met le code que l’on veut gérer, donc susceptible de lever une exception.
* Dans le bloc « **`except`** », on met le code à exécuter en cas d’exception. Il est possible de gérer plusieurs exceptions pour la(les) même(s) instruction(s).

#### Exemple :&#x20;

Gestion des exceptions du code suivant :&#x20;

```python
nombre = int(input("Entrez un nombre:"))
resultat = 10 / nombre
```

* Gestion de l'exception ***`ZeroDivisionError`*** : Le code suivant permet de détecter et gérer une exception de type ***`ZeroDivisionError`*** dans l’instruction `resultat = 10 / nombre`.

```python
nombre = int(input("Entrez un nombre:"))

try:
    resultat = 10 / nombre

except ZeroDivisionError:

    print("La valeur entrée ne doit pas être 0!")
```

* Gestion de l'exception ***`ValueError` :*** Le code suivant permet de détecter et gérer une exception de type ***`ValueError`*** dans l’instruction `nombre = int(input("Entrez un nombre:"))`.

{% code lineNumbers="true" %}

```python
try:
    nombre = int(input("Entrez un nombre:"))
    
except ValueError:

    print("La valeur entrée n'est pas un nombre.")

resultat = 10 / nombre
```

{% endcode %}

{% hint style="danger" %}
Dans l'exemple précédent, si ça rentre dans le *`except ValueError`*, la variable `nombre` ne sera pas définie à la ligne 8 `resultat = 10 / nombre`, il va y avoir un autre type d'exception.&#x20;

Lorsqu'une ligne de code dépend directement de la précédente, une solution possible serait de gérer plusieurs exceptions dans le même bloc.

```python
try:
    nombre = int(input("Entrez un nombre:"))
    resultat = 10 / nombre
except ValueError :
    print("La valeur entrée doit être un nombre entier.")
except ZeroDivisionError:
    print("On ne peut pas diviser par 0.")
```

{% endhint %}

### Syntaxe try/except/else/finally

```python
try:
    nombre = int(input("Entrez un nombre:"))
    resultat = 10 / nombre
except ValueError:
    print("La valeur entrée n'est pas un nombre")
except ZeroDivisionError:
    print("La valeur entrée ne doit pas être 0!")
except:
    print("Une erreur est survenue")
else:
    print(resultat)
finally:
    print("Fin!")
```

* Dans le bloc « **`try`** », on met le code que l’on veut gérer, donc susceptible de lever une exception.
* Dans le bloc « **`except`** », on met le code à exécuter en cas d’exception. Il est possible de gérer plusieurs exceptions pour la(les) même(s) instruction(s).
* Dans le bloc « **`else`** », on met le code à exécuter lorsqu’aucune exception ne survient.
* Dans le bloc « **`finally`** » est exécuté peu importe ce qui arrive (qu’il y ait une erreur ou non).

#### Exemple :

```python
try:
    nombre = int(input("Entrez un nombre:"))
    resultat = 10 / nombre
except ValueError:
    print("La valeur entrée n'est pas un nombre.")
except ZeroDivisionError:
    print("La valeur entrée ne doit pas être 0!")
except:
    print("Une erreur est survenue.")
else:
    print(resultat)
finally:
    print("Fin!")
```

## <mark style="color:red;">Pratiques non conseillées</mark>

{% hint style="danger" %}
Gérer plusieurs types d'exceptions de la même façon :&#x20;

```python
try:
    nombre = int(input("Entrez un nombre:"))
    resultat = 10 / nombre
except (ValueError, ZeroDivisionError) :
    print("Une erreur a eu lieu.")
```

{% endhint %}

{% hint style="danger" %}
Il n'est pas obligatoire de mentionner le type d'exception dans`except` mais ceci <mark style="color:red;">est vivement déconseillé</mark> au risque de gérer à tort tous les types d'exceptions de la même façon.

```python
try:
    nombre = int(input("Entrez un nombre:"))
    resultat = 10 / nombre
except :
    print("Une erreur a eu lieu.")
```

{% endhint %}
