Question Élever manuellement (lancer) une exception en Python


Comment puis-je déclencher une exception dans Python afin qu'il puisse être capturé plus tard via un except bloc?


1516
2018-01-12 21:07


origine


Réponses:


Comment lancer / lever manuellement une exception en Python?

Utilisez le constructeur Exception le plus spécifique qui correspond sémantiquement à votre problème.

Soyez précis dans votre message, par exemple:

raise ValueError('A very specific bad thing happened.')

Ne pas déclencher d'exceptions génériques

Évitez d'élever une exception générique. Pour l'attraper, vous devrez attraper toutes les autres exceptions plus spécifiques qui le sous-classe.

Problème 1: cacher des bugs

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

Par exemple:

def demo_bad_catch():
    try:
        raise ValueError('Represents a hidden bug, do not catch this')
        raise Exception('This is the exception you expect to handle')
    except Exception as error:
        print('Caught this error: ' + repr(error))

>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)

Problème 2: Ne prendra pas

et les captures plus spécifiques n'atteindront pas l'exception générale:

def demo_no_catch():
    try:
        raise Exception('general exceptions not caught by specific handling')
    except ValueError as e:
        print('we will not catch exception: Exception')


>>> demo_no_catch()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling

Les meilleures pratiques: raise déclaration

Au lieu de cela, utilisez le constructeur Exception le plus spécifique qui correspond sémantiquement à votre problème.

raise ValueError('A very specific bad thing happened')

ce qui permet également de transmettre un nombre arbitraire d'arguments au constructeur:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

Ces arguments sont accessibles par le args attribut sur l'objet Exception. Par exemple:

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

imprime

('message', 'foo', 'bar', 'baz')    

En Python 2.5, un réel message attribut a été ajouté à BaseException en faveur d'encourager les utilisateurs à sous-classe Exceptions et arrêter d'utiliser args, mais l'introduction de message et la dépréciation originale des args a été rétractée.

Les meilleures pratiques: except clause

Lorsque vous vous trouvez dans une clause except, vous pouvez, par exemple, consigner qu'un type spécifique d'erreur s'est produit, puis relancer. La meilleure façon de le faire tout en préservant la trace de la pile consiste à utiliser une instruction raise simple. Par exemple:

logger = logging.getLogger(__name__)

try:
    do_something_in_app_that_breaks_easily()
except AppError as error:
    logger.error(error)
    raise                 # just this!
    # raise AppError      # Don't do this, you'll lose the stack trace!

Ne modifiez pas vos erreurs ... mais si vous insistez.

Vous pouvez conserver la piletrace (et la valeur d'erreur) avec sys.exc_info(), mais c'est beaucoup plus sujet aux erreurs et a des problèmes de compatibilité entre Python 2 et 3, préfère utiliser un nu raise re-relancer.

Pour expliquer - le sys.exc_info() renvoie le type, la valeur et la traceback.

type, value, traceback = sys.exc_info()

C'est la syntaxe dans Python 2 - notez que ceci n'est pas compatible avec Python 3:

    raise AppError, error, sys.exc_info()[2] # avoid this.
    # Equivalently, as error *is* the second object:
    raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

Si vous le souhaitez, vous pouvez modifier ce qui se passe avec votre nouvelle augmentation - par ex. définir de nouveaux arguments pour l'instance:

def error():
    raise ValueError('oops!')

def catch_error_modify_message():
    try:
        error()
    except ValueError:
        error_type, error_instance, traceback = sys.exc_info()
        error_instance.args = (error_instance.args[0] + ' <modification>',)
        raise error_type, error_instance, traceback

Et nous avons conservé tout le retraçage tout en modifiant les arguments. Notez que c'est pas une bonne pratique et c'est Syntaxe invalide en Python 3 (rendant la compatibilité de conservation beaucoup plus difficile à contourner).

>>> catch_error_modify_message()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in catch_error_modify_message
  File "<stdin>", line 2, in error
ValueError: oops! <modification>

Dans Python 3:

    raise error.with_traceback(sys.exc_info()[2])

Encore une fois: évitez de manipuler manuellement les retraçages. Ses moins efficace et plus d'erreurs sujettes. Et si vous utilisez le filetage et sys.exc_info vous pouvez même obtenir un mauvais suivi (en particulier si vous utilisez la gestion des exceptions pour le flux de contrôle - que j'aurais personnellement tendance à éviter).

Python 3, chaînage d'exceptions

Dans Python 3, vous pouvez chaîner des exceptions, qui préservent les retraçages:

    raise RuntimeError('specific message') from error

Savoir:

  • ce Est-ce que permettre de changer le type d'erreur soulevé, et
  • c'est ne pas compatible avec Python 2.

Méthodes déconseillées:

Ceux-ci peuvent facilement se cacher et même entrer dans le code de production. Vous voulez lever une exception, et les faire lèvera une exception, mais pas celui prévu!

Valide en Python 2, mais pas en Python 3 est le suivant:

raise ValueError, 'message' # Don't do this, it's deprecated!

Seulement valable dans les anciennes versions de Python (2.4 et moins), vous pouvez toujours voir des personnes élever des chaînes:

raise 'message' # really really wrong. don't do this.

Dans toutes les versions modernes, cela déclenchera réellement un TypeError, parce que vous n'élevez pas un type BaseException. Si vous ne vérifiez pas la bonne exception et que vous n'avez pas d'examinateur conscient du problème, il pourrait entrer en production.

Exemple d'utilisation

Je lève des exceptions pour avertir les consommateurs de mon API s'ils ne l'utilisent pas correctement:

def api_func(foo):
    '''foo should be either 'baz' or 'bar'. returns something very useful.'''
    if foo not in _ALLOWED_ARGS:
        raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))

Créez vos propres types d'erreur quand à propos

"Je veux faire une erreur sur le but, de sorte qu'il irait dans l'exception"

Vous pouvez créer vos propres types d'erreurs, si vous voulez indiquer que quelque chose de spécifique est incorrect avec votre application, il suffit de sous-classer le point approprié dans la hiérarchie des exceptions:

class MyAppLookupError(LookupError):
    '''raise this when there's a lookup error for my app'''

et utilisation:

if important_key not in resource_dict and not ok_to_be_missing:
    raise MyAppLookupError('resource is missing, and that is not ok.')

1890
2018-06-05 16:30



NE FAITES PAS. Élever un nu Exception est absolument ne pas la bonne chose à faire; voir L'excellente réponse d'Aaron Hall au lieu.

Vous ne pouvez pas obtenir beaucoup plus pythonique que ceci:

raise Exception("I know python!")

Voir la déclaration de relance docs pour python si vous souhaitez plus d'informations.


541
2018-01-12 21:08



Pour le cas courant où vous devez lancer une exception en réponse à des conditions inattendues, et que vous n'avez jamais l'intention d'intercepter, mais simplement échouer rapidement pour vous permettre de déboguer à partir de là si jamais cela arrive - le plus logique semble être AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)

29
2018-05-19 04:55



En Python3, il existe 4 syntaxes différentes pour les exceptions de rasage:

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1. lever l'exception contre 2. lever l'exception (args)

Si tu utilises raise exception (args)  pour lever une exception, puis la args sera imprimé lorsque vous imprimez l'objet exception - comme indiqué dans l'exemple ci-dessous.

  #raise exception (args)
    try:
        raise ValueError("I have raised an Exception")
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error I have raised an Exception 



  #raise execption 
    try:
        raise ValueError
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error 

3.raise

raise instruction sans aucun argument re-soulève la dernière exception. Ceci est utile si vous avez besoin d'effectuer certaines actions après avoir attrapé l'exception, puis que vous souhaitez l'augmenter de nouveau. Mais s'il n'y avait pas d'exception avant, raise déclaration soulève TypeError Exception.

def somefunction():
    print("some cleaning")

a=10
b=0 
result=None

try:
    result=a/b
    print(result)

except Exception:            #Output ->
    somefunction()           #some cleaning
    raise                    #Traceback (most recent call last):
                             #File "python", line 8, in <module>
                             #ZeroDivisionError: division by zero

4. lever l'exception (args) d'origine_exception

Cette instruction est utilisée pour créer un chaînage d'exceptions dans lequel une exception déclenchée en réponse à une autre exception peut contenir les détails de l'exception d'origine, comme indiqué dans l'exemple ci-dessous.

class MyCustomException(Exception):
pass

a=10
b=0 
reuslt=None
try:
    try:
        result=a/b

    except ZeroDivisionError as exp:
        print("ZeroDivisionError -- ",exp)
        raise MyCustomException("Zero Division ") from exp

except MyCustomException as exp:
        print("MyException",exp)
        print(exp.__cause__)

Sortie:

ZeroDivisionError --  division by zero
MyException Zero Division 
division by zero

22
2017-11-08 17:54



Lisez d'abord les réponses existantes, ceci n'est qu'un addendum.

Notez que vous pouvez lever des exceptions avec ou sans arguments.

Exemple:

raise SystemExit

quitte le programme, mais vous voudrez peut-être savoir ce qui s'est passé. Donc, vous pouvez l'utiliser.

raise SystemExit("program exited")

cela affichera "programme sorti" sur stderr avant de fermer le programme.


5
2018-03-29 11:59