| @@ -5,16 +5,7 @@ | |||
| \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 | |||
| def une_fonction(): | |||
| @@ -39,8 +30,9 @@ Traceback (most recent call last): | |||
| ZeroDivisionError: division by zero | |||
| ``` | |||
| ZeroDivisionError est une *classe*. | |||
| # Les backtraces | |||
| # Exemple modifié | |||
| ```python | |||
| def une_fonction(diviseur): | |||
| @@ -52,7 +44,8 @@ def une_autre_fonction(): | |||
| une_autre_fonction() | |||
| ``` | |||
| # Les backtraces | |||
| # Exemple modifié | |||
| ``` | |||
| Traceback (most recent call last): | |||
| @@ -65,16 +58,49 @@ Traceback (most recent call last): | |||
| 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 | |||
| ```python | |||
| @@ -85,16 +111,11 @@ except ZeroDivisionError: | |||
| 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 | |||
| On peut mettre plusieurs blocs de `except` | |||
| ```python | |||
| try: | |||
| @@ -105,43 +126,71 @@ except FileNotFoundError: | |||
| 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 | |||
| # 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 | |||
| 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 | |||
| try: | |||
| open(filename): | |||
| file = open(filename) | |||
| 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 | |||
| if truc: | |||
| @@ -150,6 +199,8 @@ if truc: | |||
| raise MyError("kaboom!") | |||
| ```` | |||
| # Attention à la position du except | |||
| ```python | |||
| if truc: | |||
| if machin: | |||
| @@ -161,6 +212,7 @@ if truc: | |||
| ``` | |||
| # Attention à la position du except | |||
| ```python | |||
| 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) | |||