Update first chapters and new questions

Updated first chapter slides.
Added new questions in the new training section.
This commit is contained in:
2025-07-07 21:18:04 +02:00
parent bea28eca14
commit 77aa231f5b
11 changed files with 416 additions and 250 deletions

View File

@ -9,26 +9,36 @@ author: Steve Kossouho
## Exceptions
En Python, une exception est une erreur qui se produit pendant l'exécution de votre code. En tant que développeur, vous pouvez choisir ce que vous souhaitez faire quand une exception se produit, plutôt que de laisser le programme s'arrêter avec un message d'erreur. Les exceptions s'opposent entre autres aux erreurs de syntaxe, où l'interpréteur n'est pas même en mesure d'exécuter votre code.
En Python, une [exception]{.naming} est une erreur qui se produit pendant l'exécution de votre code.
En tant que développeur, vous pouvez **intercepter** une exception, et dire à Python ce que vous souhaitez faire
afin d'empêcher le programme de se terminer prématurément si ce n'est pas nécessaire.
----
### Jargon des exceptions
- `Lever une exception` : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script. Les exceptions générées par Python sont d'un type qui dépend de l'erreur rencontrée. Elles font toutes partie d'une hiérarchie dont le type le plus générique est nommé `Exception`. (voir programmation orientée objet et hiérarchie des classes d'exception)
- `Traceback` : <span style="color:red">Texte qui apparaît</span> dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception.
- [Lever une exception]{.naming} : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script.
- [Traceback]{.naming} : <span style="color:#F04">Texte qui apparaît</span> dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception.
Les exceptions levées par Python sont d'un type qui dépend de l'erreur rencontrée (ex. `TypeError`{.python}).
Tous ces types font partie d'une hiérarchie dont le type le plus générique est nommé `Exception`.
Théoriquement, un développeur peut créer son propre type d'exception lorsqu'il développe des bibliothèques.
----
### Exemple d'exception
### Exemple de gestion d'exception
Dans l'exemple ci-dessous, on effectue une division par zéro, mais on pourrait accéder à un mauvais indice de liste, une mauvaise clé de dictionnaire, un fichier verrouillé…
Dans l'exemple ci-dessous, on effectue une division par zéro, ce qui est toujours une erreur, mais on pourrait accéder
à un mauvais index de liste, à une clé de dictionnaire inexistante, ou encore à un fichier verrouillé…
```{.python .numberLines}
```python {.numberLines}
try:
15 / 0 # erreur évidente pour l'exemple
except ZeroDivisionError:
pass
resultat = 15 / 0 # erreur évidente pour l'exemple
print("Cette ligne ne sera jamais exécutée.")
except ZeroDivisionError: # Ici, on intercepte spécifiquement le type d'erreur produit par la division
print("Le résultat n'a pas pu être calculé.")
print("Fin du programme.")
```
Gestion des erreurs de division par zéro
@ -39,30 +49,32 @@ Gestion des erreurs de division par zéro
----
### À ne pas faire
### Mauvaise pratique sur les exceptions
Il est déconseillé d'utiliser directement la classe `Exception` (ou rien, d'ailleurs) avec la clause `except`;
ceci a pour effet de pousser votre code à réagir exactement de la même manière pour tous les cas de figure.
Si vous le tentez malgré tout, affichez ou conservez le traceback, vous me remercierez plus tard :
Il est **ardemment** déconseillé d'utiliser directement la classe `Exception`{.python} (ou ne rien préciser, d'ailleurs) avec la clause `except`{.python};
une clause trop générique intercepte **tous** les problèmes rencontrés dans le bloc `try`{.python}.
Dans certains cas, cela vous fera manquer des erreurs que vous ne souhaitez pas traiter avec le même bloc `except`{.python}.
```{.python .numberLines}
Une règle d'or de Python indique que dans le cas où vous masquez tous les types d'exception sans distinction, vous
ne devez jamais le faire silencieusement; affichez le problème ou consignez-le quelque part :
```python {.numberLines}
import traceback
try:
print(15 / 0)
except Exception: # ou except:
traceback.print_exc() # Affiche le traceback dans la console
traceback.print_exc() # Affiche le traceback dans la console sans planter
```
Voir [antipattern sur les exceptions pour plus d'info](https://realpython.com/the-most-diabolical-python-antipattern/)
----
### Un bloc `except`, plusieurs exceptions
On peut même avoir des blocs `except`{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit de les indiquer dans un tuple :
On peut même avoir des blocs `except`{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit d'indiquer
un tuple de classes d'exceptions à la clause `except`{.python} :
```{.python .numberLines}
```python {.numberLines}
try:
pass # ou faire autre chose
except (TypeError, ValueError):
@ -76,7 +88,7 @@ except (TypeError, ValueError):
On peut, à l'instar de la structure `if/elif/else`, faire suivre le bloc `try`{.python} de
plusieurs blocs `except`{.python} :
```{.python .numberLines}
```python {.numberLines}
try:
print("Code à essayer")
except ValueError:
@ -85,15 +97,20 @@ except TypeError:
print("Code pour TypeError")
```
Python évaluera la structure de haut en bas. Si une erreur se produit dans le bloc `try`{.python},
Python évaluera d'abord le premier bloc `except`{.python}, de la même manière que pour toutes les structures de code.
----
Si aucun des blocs `except`{.python} ne gère précisément l'erreur qui se produit dans le bloc `try`{.python},
alors l'interpréteur Python plante avec un traceback dans la console, comme attendu.
```{.python .numberLines}
```python {.numberLines}
try:
1 / 0
except NameError:
except TypeError: # pas la bonne exception
pass
except NameError: # pas la bonne exception non plus
pass
```
@ -104,9 +121,9 @@ except NameError:
La structure `try`{.python}...`except`{.python} peut être accompagnée d'un bloc `else`{.python}. Ce bloc
sera exécuté si aucun des blocs `except`{.python} précédents n'a été exécuté (comme dans une structure `if`{.python}) :
```{.python .numberLines}
```python {.numberLines}
try:
value = input("Saisissez un nombre entier :")
value = input("Saisissez un nombre entier : ")
value = int(value)
except ValueError:
value = None
@ -121,7 +138,7 @@ else:
Pour finir, il existe un bloc `finally`{.python}, dont le bloc est *toujours* exécuté, même si le programme doit planter :
```{.python .numberLines}
```python {.numberLines}
try:
15 / 0
except KeyError:
@ -134,10 +151,12 @@ En général, on imagine l'utiliser lorsqu'on souhaite penser à toujours libér
----
On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer.
C'est généralement le cas lorsque l'on fournit une API utilisable par d'autres développeurs.
### Lever une exception
```{.python .numberLines}
On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer.
C'est généralement le cas lorsque l'on développe une bibliothèque utilisable par d'autres développeurs.
```python {.numberLines}
def do_something(value):
if not isinstance(value, int): # si value n'est pas un entier
raise TypeError("Value must be an integer.")