215 votes

Comment puis-je faire apparaître la même exception avec un message personnalisé en Python ?

J'ai ceci try dans mon code :

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise ValueError(errmsg)

A proprement parler, je soulève en fait un autre ValueError et non le ValueError jeté par do_something...() que l'on appelle err dans ce cas. Comment joindre un message personnalisé à err ? J'ai essayé le code suivant mais il échoue en raison de err , a ValueError instance ne pouvant être appelé :

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)

274voto

Ben Points 1707

Si vous avez la chance de ne supporter que python 3.x, cela devient une véritable merveille :)

augmenter de

Nous pouvons enchaîner les exceptions en utilisant augmenter de .

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks') from e

Dans ce cas, l'exception que votre appelant doit attraper a le numéro de ligne de l'endroit où nous levons notre exception.

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

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

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks') from e
Exception: Smelly socks

Remarquez que l'exception du bas ne contient que la trace de la pile à partir de laquelle nous avons levé notre exception. L'appelant peut toujours obtenir l'exception originale en accédant au fichier __cause__ de l'exception qu'ils capturent.

avec_traceback

Ou vous pouvez utiliser avec_traceback .

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks').with_traceback(e.__traceback__)

En utilisant cette forme, l'exception que votre appelant attrapera aura la trace de l'endroit où l'erreur originale s'est produite.

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception('Smelly socks').with_traceback(e.__traceback__)
  File "test.py", line 2, in <module>
    1 / 0
Exception: Smelly socks

Remarquez que l'exception du bas comporte la ligne où nous avons effectué la division invalide ainsi que la ligne où nous relançons l'exception.

118voto

Johan Lundberg Points 5835

Mise à jour : Pour Python 3, vérifiez La réponse de Ben


Pour joindre un message à l'exception en cours et la relancer : (le try/except extérieur est juste pour montrer l'effet)

Pour python 2.x où x>=6 :

try:
    try:
      raise ValueError  # something bad...
    except ValueError as err:
      err.message=err.message+" hello"
      raise              # re-raise current exception
except ValueError as e:
    print(" got error of type "+ str(type(e))+" with message " +e.message)

Cela va aussi faire la bonne chose si err est dérivé de de ValueError . Par exemple UnicodeDecodeError .

Notez que vous pouvez ajouter ce que vous voulez à err . Par exemple err.problematic_array=[1,2,3] .


Edit : @Ducan signale dans un commentaire que ce qui précède ne fonctionne pas avec python 3 car .message n'est pas un membre de ValueError . À la place, vous pouvez utiliser ceci (python 2.6 ou plus ou 3.x valide) :

try:
    try:
      raise ValueError
    except ValueError as err:
       if not err.args: 
           err.args=('',)
       err.args = err.args + ("hello",)
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e.args))

Edit2 :

Selon l'objectif recherché, vous pouvez également choisir d'ajouter les informations supplémentaires sous votre propre nom de variable. Pour python2 et python3 :

try:
    try:
      raise ValueError
    except ValueError as err:
       err.extra_info = "hello"
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e))
    if 'extra_info' in dir(e):
       print e.extra_info

11voto

Chris Johnson Points 2887

Il semble que toutes les réponses ajoutent des informations à e.args[0], modifiant ainsi le message d'erreur existant. Y a-t-il un inconvénient à étendre plutôt le tuple args ? Je pense que l'avantage possible est que vous pouvez laisser le message d'erreur d'origine seul pour les cas où l'analyse syntaxique de cette chaîne est nécessaire ; et vous pouvez ajouter plusieurs éléments au tuple si votre traitement personnalisé des erreurs produit plusieurs messages ou codes d'erreur, pour les cas où le retour de trace serait analysé par programme (comme via un outil de surveillance du système).

## Approach #1, if the exception may not be derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args = (e.args if e.args else tuple()) + ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

ou

## Approach #2, if the exception is always derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args += ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

Voyez-vous un inconvénient à cette approche ?

8voto

eumiro Points 56644
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

des empreintes :

There is a problem: invalid literal for int() with base 10: 'a'

8voto

shrewmouse Points 1683

Cela ne fonctionne qu'avec Python 3 . Vous pouvez modifier les arguments originaux de l'exception et ajouter vos propres arguments.

Une exception se souvient des arguments avec lesquels elle a été créée. Je suppose que c'est pour que vous puissiez modifier l'exception.

Dans la fonction reraise nous ajoutons aux arguments originaux de l'exception tous les nouveaux arguments que nous voulons (comme un message). Enfin, nous relançons l'exception tout en préservant l'historique de la trace.

def reraise(e, *args):
  '''re-raise an exception with extra arguments
  :param e: The exception to reraise
  :param args: Extra args to add to the exception
  '''

  # e.args is a tuple of arguments that the exception with instantiated with.
  #
  e.args = args + e.args

  # Recreate the expection and preserve the traceback info so thta we can see 
  # where this exception originated.
  #
  raise e.with_traceback(e.__traceback__)   

def bad():
  raise ValueError('bad')

def very():
  try:
    bad()
  except Exception as e:
    reraise(e, 'very')

def very_very():
  try:
    very()
  except Exception as e:
    reraise(e, 'very')

very_very()

sortie

Traceback (most recent call last):
  File "main.py", line 35, in <module>
    very_very()
  File "main.py", line 30, in very_very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 28, in very_very
    very()
  File "main.py", line 24, in very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 22, in very
    bad()
  File "main.py", line 18, in bad
    raise ValueError('bad')
ValueError: ('very', 'very', 'bad')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X