| @@ -5,16 +5,7 @@ | |||||
| \center \huge Exceptions | \center \huge Exceptions | ||||
| # Examples d'erreurs | |||||
| * division par zéro | |||||
| * dépassement d'un tableau | |||||
| * clé non trouvée dans un dico | |||||
| * opération entre types incompatibles | |||||
| * le fichier n'existe pas | |||||
| * la variable n'existe pas | |||||
| # Les backtraces | |||||
| # Exemple | |||||
| ```python | ```python | ||||
| def une_fonction(): | def une_fonction(): | ||||
| @@ -39,8 +30,9 @@ Traceback (most recent call last): | |||||
| ZeroDivisionError: division by zero | ZeroDivisionError: division by zero | ||||
| ``` | ``` | ||||
| ZeroDivisionError est une *classe*. | |||||
| # Les backtraces | |||||
| # Exemple modifié | |||||
| ```python | ```python | ||||
| def une_fonction(diviseur): | def une_fonction(diviseur): | ||||
| @@ -52,7 +44,8 @@ def une_autre_fonction(): | |||||
| une_autre_fonction() | une_autre_fonction() | ||||
| ``` | ``` | ||||
| # Les backtraces | |||||
| # Exemple modifié | |||||
| ``` | ``` | ||||
| Traceback (most recent call last): | Traceback (most recent call last): | ||||
| @@ -65,16 +58,49 @@ Traceback (most recent call last): | |||||
| ZeroDivisionError: division by zero | ZeroDivisionError: division by zero | ||||
| ``` | ``` | ||||
| # Lever une exception | |||||
| **Prenez le temps de lire les backtraces soigneusement!** | |||||
| ```python | |||||
| def retirer_somme(compte, montant): | |||||
| solde = ... | |||||
| if montant >= solde: | |||||
| raise ValueError("montant supérieur au solde!") | |||||
| # Exemples d'erreurs | |||||
| * `b += 2` - **NameError** | |||||
| * `a / 9` - **ZeroDivisionError** | |||||
| * `my_list[42]` - **IndexError** | |||||
| * ``my_dict["bad-key"]`` - **KeyError** | |||||
| * `1 + "two"` - **TypeError** | |||||
| * `open("badpath")` - **FileNotFoundError** | |||||
| # Hiérarchie d'exceptions (simplifiée) | |||||
| ``` | |||||
| BaseException | |||||
| +-- SystemExit | |||||
| +-- KeyboardInterrupt | |||||
| +-- Exception | |||||
| +-- ArithmeticError | |||||
| | +-- ZeroDivisionError | |||||
| +-- LookupError | |||||
| | +-- IndexError | |||||
| | +-- KeyError | |||||
| +-- OSError | |||||
| | +-- FileNotFoundError | |||||
| +-- TypeError | |||||
| +-- ValueError | |||||
| ``` | ``` | ||||
| Liste complète dans la documentation: | |||||
| https://docs.python.org/fr/3/library/exceptions.html#exception-hierarchy | |||||
| # KeyboardInterrupt et SystemExit | |||||
| * `KeyboardInterrupt` est levée quand on fait `ctrl-c`. | |||||
| * `SystemExit` est levé quand on utilise `sys.exit()` | |||||
| * Python cache la backtrace dans ce cas-là | |||||
| * Pas utile de l'attrapper en général | |||||
| # Attraper une exception | # Attraper une exception | ||||
| ```python | ```python | ||||
| @@ -85,16 +111,11 @@ except ZeroDivisionError: | |||||
| print("someone tried to divide by zero!") | print("someone tried to divide by zero!") | ||||
| ``` | ``` | ||||
| * Note: si l'exception n'est pas une fille de la classe attrapee, c'est rate. | |||||
| # Attraper une exception | |||||
| * On peut mettre plusieurs blocs de `except` | |||||
| * On peut attraper plusieurs exceptions d'un coup | |||||
| * Note: si l'exception n'est pas une fille de la classe attrapée, c'est raté. | |||||
| # Attraper une exception | # Attraper une exception | ||||
| On peut mettre plusieurs blocs de `except` | |||||
| ```python | ```python | ||||
| try: | try: | ||||
| @@ -105,43 +126,71 @@ except FileNotFoundError: | |||||
| print("file not found") | print("file not found") | ||||
| ``` | ``` | ||||
| # Attraper une exception | |||||
| On peut attraper plusieurs exceptions d'un coup | |||||
| Attention aux bare except | |||||
| # Hiérarchies | |||||
| À connaître | |||||
| À utiliser si vous faites une librairie. | |||||
| ```python | |||||
| try: | |||||
| something_dangerous() | |||||
| except (ZeroDivisionError, FileNotFoundError): | |||||
| print("something bad happened") | |||||
| ``` | |||||
| # finally, else | # finally, else | ||||
| # WBYL et EAFP | |||||
| Watch Before You Leap | |||||
| Easier to Ask for Forgiveness than Permission | |||||
| ```python | |||||
| try: | |||||
| something_dangerous() | |||||
| except SomeError: | |||||
| print("something bad happened") | |||||
| else: | |||||
| print("everything went well") | |||||
| finally: | |||||
| clean_up() | |||||
| ``` | |||||
| # WBYL | |||||
| fichiers encore: | |||||
| * Watch Before You Leap | |||||
| ```python | ```python | ||||
| if exists(): | if exists(): | ||||
| if pas_un_dossier(): | |||||
| if j_ai_les_droits_en_lecture(): | |||||
| open(filename): | |||||
| if pas_un_dossier(): | |||||
| if j_ai_les_droits_en_lecture(): | |||||
| open(filename): | |||||
| ``` | ``` | ||||
| # EAFP | |||||
| * Easier to Ask for Forgiveness than Permission | |||||
| ```python | ```python | ||||
| try: | try: | ||||
| open(filename): | |||||
| file = open(filename) | |||||
| catch IOError: | catch IOError: | ||||
| ... | ... | ||||
| finally: | |||||
| file.close() | |||||
| ``` | ``` | ||||
| # Avec with | |||||
| Pas besoin de `finally` :) | |||||
| # avec with | |||||
| ```python | |||||
| try: | |||||
| with file = open(filename): | |||||
| lines = file.readlines() | |||||
| except FileNotFoundError: | |||||
| print("Fichier non trouvé") | |||||
| ``` | |||||
| L'exception est capturée, le fichier est fermé, puis l'exception est | |||||
| levée à nouveau. | |||||
| # attention a ou vous mettez except | |||||
| # Attention à la position du except | |||||
| ```python | ```python | ||||
| if truc: | if truc: | ||||
| @@ -150,6 +199,8 @@ if truc: | |||||
| raise MyError("kaboom!") | raise MyError("kaboom!") | ||||
| ```` | ```` | ||||
| # Attention à la position du except | |||||
| ```python | ```python | ||||
| if truc: | if truc: | ||||
| if machin: | if machin: | ||||
| @@ -161,6 +212,7 @@ if truc: | |||||
| ``` | ``` | ||||
| # Attention à la position du except | |||||
| ```python | ```python | ||||
| if truc: | if truc: | ||||
| @@ -173,9 +225,45 @@ if truc: | |||||
| ```` | ```` | ||||
| # Accédér aux détails de l'exception | |||||
| * Avec `as`: | |||||
| ```python | |||||
| try: | |||||
| something_dangerous() | |||||
| except FileNotFoundError as error: | |||||
| print("file not found:", error.filename) | |||||
| ``` | |||||
| \vfill | |||||
| # Accédér aux détails de l'exceptions | |||||
| Voir la documentation pour les attributs disponibles. | |||||
| # Lever une exception | |||||
| * Avec raise | |||||
| ```python | |||||
| def retirer_somme(compte, montant): | |||||
| solde = ... | |||||
| if montant >= solde: | |||||
| raise ValueError("montant supérieur au solde!") | |||||
| ``` | |||||
| # Créer vos propres exceptions | |||||
| Toujours hériter de `Exception`. | |||||
| ```python | |||||
| class BankError(Exception): | |||||
| .... | |||||
| class NotEnoughMoney(BankError): | |||||
| def __init__(self, amount, withdrawal): | |||||
| self.amount = amount | |||||
| self.withdrawal = withdrawal | |||||
| ``` | |||||
| * Avec `as` | |||||
| * Attrribut `args` | |||||
| * Parfois d'autres atttributs (voir la doc) | |||||