Recherche…


Introduction

Les erreurs détectées lors de l'exécution s'appellent des exceptions et ne sont pas inconditionnellement fatales. La plupart des exceptions ne sont pas gérées par les programmes. il est possible d'écrire des programmes qui traitent les exceptions sélectionnées. Il existe des fonctionnalités spécifiques à Python pour gérer les exceptions et la logique des exceptions. De plus, les exceptions ont une hiérarchie de types enrichis, toutes héritant du type BaseException .

Syntaxe

  • lever l' exception
  • raise # re-relance une exception qui a déjà été soulevée
  • déclenche une exception de cause # Python 3 - définit la cause des exceptions
  • déclenche une exception à partir de None # Python 3 - supprime tous les contextes d'exception
  • essayer:
  • sauf [types d'exception] [ comme identifiant ] :
  • autre:
  • enfin:

Augmenter les exceptions

Si votre code rencontre une condition qu'il ne sait pas gérer, telle qu'un paramètre incorrect, il doit déclencher l'exception appropriée.

def even_the_odds(odds):
    if odds % 2 != 1:
        raise ValueError("Did not get an odd number")
    
    return odds + 1

Prendre des exceptions

Utilisez try...except: pour attraper des exceptions. Vous devez spécifier une exception aussi précise que possible:

try:
    x = 5 / 0
except ZeroDivisionError as e:
    # `e` is the exception object
    print("Got a divide by zero! The exception was:", e)
    # handle exceptional case
    x = 0  
finally:
    print "The END"
    # it runs no matter what execute.

La classe d'exception spécifiée - dans ce cas, ZeroDivisionError - ZeroDivisionError toute exception ZeroDivisionError cette classe ou à une sous-classe de cette exception.

Par exemple, ZeroDivisionError est une sous-classe de ArithmeticError :

>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)

Et ainsi, les éléments suivants attraperont toujours le ZeroDivisionError :

try:
    5 / 0
except ArithmeticError:
    print("Got arithmetic error")

Lancer le code de nettoyage avec finalement

Parfois, vous voudrez peut-être que quelque chose se produise, quelle que soit l'exception, par exemple, si vous devez nettoyer certaines ressources.

Le bloc finally d'une clause try se produira, que des exceptions aient été soulevées ou non.

resource = allocate_some_expensive_resource()
try:
    do_stuff(resource)
except SomeException as e:
    log_error(e)
    raise  # re-raise the error
finally:
    free_expensive_resource(resource)

Ce modèle est souvent mieux géré avec les gestionnaires de contexte (en utilisant l'instruction with ).

Relancer les exceptions

Parfois, vous voulez attraper une exception simplement pour l'inspecter, par exemple à des fins de journalisation. Après l'inspection, vous souhaitez que l'exception continue à se propager comme auparavant.

Dans ce cas, utilisez simplement l'instruction raise sans paramètres.

try:
    5 / 0
except ZeroDivisionError:
    print("Got an error")
    raise

Gardez à l'esprit que quelqu'un plus haut dans la pile de l'appelant peut toujours attraper l'exception et la gérer d'une manière ou d'une autre. Le résultat final pourrait être une nuisance dans ce cas car cela se produira dans tous les cas (attrapé ou non attrapé). Donc, il serait peut-être préférable de soulever une exception différente, contenant votre commentaire sur la situation ainsi que l'exception initiale:

try:
    5 / 0
except ZeroDivisionError as e:
    raise ZeroDivisionError("Got an error", e)

Mais cela a l'inconvénient de réduire la trace d'exception à exactement cette raise tandis que raise sans argument conserve la trace d'exception d'origine.

En Python 3, vous pouvez conserver la pile d'origine en utilisant la syntaxe raise - from :

    raise ZeroDivisionError("Got an error") from e

Chaîne d'exceptions avec augmentation de

Lors du traitement d'une exception, vous souhaiterez peut-être générer une autre exception. Par exemple, si vous obtenez une IOError lors de la lecture d'un fichier, vous souhaiterez peut-être générer une erreur spécifique à l'application pour la présenter aux utilisateurs de votre bibliothèque.

Python 3.x 3.0

Vous pouvez enchaîner les exceptions pour montrer comment le traitement des exceptions s'est déroulé:

>>> try:
    5 / 0
except ZeroDivisionError as e:
    raise ValueError("Division failed") from e

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: Division failed

Hiérarchie des exceptions

La gestion des exceptions se produit en fonction d'une hiérarchie d'exceptions, déterminée par la structure d'héritage des classes d'exception.

Par exemple, IOError et OSError sont deux sous-classes de EnvironmentError . Le code qui IOError une IOError pas une OSError . Toutefois, le code qui intercepte une EnvironmentError intercepte à la fois IOError s et OSError s.

La hiérarchie des exceptions intégrées:

Python 2.x 2.3
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning
Python 3.x 3.0
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Les exceptions sont des objets aussi

Les exceptions ne sont que des objets Python classiques qui héritent de BaseException . Un script Python peut utiliser l'instruction raise pour interrompre l'exécution, entraînant Python à imprimer une trace de pile de la pile d'appels à ce stade et une représentation de l'instance d'exception. Par exemple:

>>> def failing_function():
...     raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in failing_function
ValueError: Example error!

qui dit qu'un ValueError avec le message 'Example error!' a été failing_function() par notre failing_function() , qui a été exécuté dans l’interpréteur.

Le code d'appel peut choisir de gérer tous les types d'exception qu'un appel peut générer:

>>> try:
...     failing_function()
... except ValueError:
...     print('Handled the error')
Handled the error

Vous pouvez mettre la main sur les objets d'exception en les affectant dans la partie except... du code de gestion des exceptions:

>>> try:
...     failing_function()
... except ValueError as e:
...     print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)

Une liste complète des exceptions Python intégrées avec leurs descriptions se trouve dans la documentation Python: https://docs.python.org/3.5/library/exceptions.html . Et voici la liste complète hiérarchisée: Hiérarchie des exceptions .

Création de types d'exception personnalisés

Créez une classe héritant d' Exception :

class FooException(Exception):
    pass
try:
    raise FooException("insert description here")
except FooException:
    print("A FooException was raised.")

ou un autre type d'exception:

class NegativeError(ValueError):
      pass

def foo(x):
    # function that only accepts positive values of x
    if x < 0:
        raise NegativeError("Cannot process negative numbers")
    ...  # rest of function body
try:
    result = foo(int(input("Enter a positive integer: ")))  # raw_input in Python 2.x
except NegativeError:
    print("You entered a negative number!")
else:
    print("The result was " + str(result))

Ne pas attraper tout!

Bien qu'il soit souvent tentant d'attraper chaque Exception :

try:
    very_difficult_function()
except Exception:
    # log / try to reconnect / exit gratiously
finally:
    print "The END"
    # it runs no matter what execute.

Ou même tout ce qui inclut BaseException et tous ses enfants, y compris Exception ):

try:
    even_more_difficult_function()
except:
    pass  # do whatever needed

Dans la plupart des cas, c'est une mauvaise pratique. Cela peut prendre plus de temps que prévu, comme SystemExit , KeyboardInterrupt et MemoryError , chacun d'entre eux devant généralement être traité différemment des erreurs système ou logiques habituelles. Cela signifie également qu'il n'y a pas de compréhension claire de ce que le code interne peut faire de mal et comment récupérer correctement de cette condition. Si vous attrapez toutes les erreurs, vous ne saurez pas quelle erreur s'est produite ou comment y remédier.

Ceci est plus communément appelé «masquage de bogue» et devrait être évité. Laissez votre programme tomber en panne au lieu d'échouer silencieusement ou pire encore, en échouant à un niveau d'exécution plus profond. (Imaginez que c'est un système transactionnel)

Habituellement, ces constructions sont utilisées au niveau le plus externe du programme et enregistrent les détails de l'erreur afin que le bogue puisse être corrigé ou que l'erreur soit traitée de manière plus spécifique.

Prendre plusieurs exceptions

Il existe plusieurs moyens de détecter les exceptions multiples .

La première consiste à créer un tuple des types d'exception que vous souhaitez capturer et gérer de la même manière. Cet exemple entraînera le code à ignorer les exceptions KeyError et AttributeError .

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except (KeyError, AttributeError) as e:
    print("A KeyError or an AttributeError exception has been caught.")

Si vous souhaitez gérer différentes exceptions de différentes manières, vous pouvez fournir un bloc d'exception distinct pour chaque type. Dans cet exemple, nous interceptons toujours KeyError et AttributeError , mais gérons les exceptions de différentes manières.

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except KeyError as e:
    print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
    print("An AttributeError has occurred. Exception message:", e)

Exemples pratiques de gestion des exceptions

Entrée utilisateur

Imaginez que vous souhaitiez qu'un utilisateur entre un numéro via une input . Vous voulez vous assurer que l'entrée est un nombre. Vous pouvez utiliser try / except ceci:

Python 3.x 3.0
while True:
    try:
        nb = int(input('Enter a number: '))
        break
    except ValueError:
        print('This is not a number, try again.')

Remarque: Python 2.x utiliserait plutôt raw_input ; la fonction input existe dans Python 2.x mais a une sémantique différente. Dans l'exemple ci-dessus, input accepterait également des expressions telles que 2 + 2 qui évaluent un nombre.

Si l'entrée n'a pas pu être convertie en entier, une valeur ValueError est ValueError . Vous pouvez l'attraper avec, except . Si aucune exception est levée, la break saute hors de la boucle. Après la boucle, nb contient un entier.

Dictionnaires

Imaginez que vous itérez une liste d'entiers consécutifs, comme range(n) , et vous avez une liste de dictionnaires d qui contient des informations sur les choses à faire lorsque vous rencontrez des entiers particuliers, dites sauter le d[i] ones suivantes.

d = [{7: 3}, {25: 9}, {38: 5}]

for i in range(len(d)):
    do_stuff(i)
    try:
       dic = d[i]
       i += dic[i]
    except KeyError:
       i += 1

Un KeyError sera KeyError lorsque vous essayez d'obtenir une valeur d'un dictionnaire pour une clé qui n'existe pas.

Autre

Le code dans un bloc else ne sera exécuté que si aucune exception n'a été déclenchée par le code dans le bloc try . Ceci est utile si vous ne voulez pas exécuter du code si une exception est levée, mais vous ne voulez pas que les exceptions lancées par ce code soient interceptées.

Par exemple:

try:
    data = {1: 'one', 2: 'two'}
    print(data[1])
except KeyError as e:
    print('key not found')
else:
    raise ValueError()
# Output: one
# Output: ValueError

Notez que ce genre d' else: ne peut pas être combiné avec un if la clause elif dans un elif . Si vous avez un public if elle doit rester en retrait en dessous d' else: :

try:
    ...
except ...:
    ...
else:
    if ...:
        ...
    elif ...:
        ...
    else:
        ...


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow