Comment puis-je lever la même Exception avec un message personnalisé en Python?

J'ai ce bloc try dans mon code:

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

Strictement parlant, je soulève en fait un autre ValueError, pas le ValueError lancé par do_something...(), qui est appelé err dans ce cas. Comment joindre un message personnalisé à err? J'ai essayer le code suivant mais échoue en raison de err, un ValueError exemple, n'étant pas exigible:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)
90
demandé sur Kit 2012-02-06 12:07:56

10 réponses

Update: pour Python 3, Vérifiez la réponse de Ben


Pour attacher un message à l'exception actuelle et le relancer: (l'essai externe / except 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 permettra également de faire la bonne chose si err est dérivés à partir de ValueError. Par exemple UnicodeDecodeError.

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


Modifier: @points Ducan dans un commentaire, ce qui précède ne fonctionne pas avec python 3 puisque .message n'est pas membre de ValueError. Au lieu de cela, vous pouvez utiliser ceci (Python 2.6 valide ou plus tard ou 3.x):

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 le but, vous pouvez également opter pour l'ajout des 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
65
répondu Johan Lundberg 2016-08-01 15:42:59

Je me rends compte que cette question existe depuis un certain temps, mais une fois que vous avez la chance de ne supporter que python 3.x, cela devient vraiment une chose de beauté:)

Augmenter à partir de

Nous pouvons enchaîner les exceptions en utilisant raise à partir de .

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

Dans ce cas, l'exception que votre appelant attraperait a le numéro de ligne de l'endroit où nous soulevons 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

Notez que l'exception inférieure a seulement la stacktrace d'où nous avons soulevé notre exception. Votre appelant pourrait toujours obtenir l'exception d'origine en accédant à l'attribut __cause__ de l'exception qu'ils attrapent.

With_traceback

, Ou vous pouvez utiliser with_traceback.

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

En utilisant ce formulaire, l'exception que votre appelant attraperait a le retraçage de l'endroit où l'erreur d'origine 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

Notez que l'exception du bas a la ligne où nous avons effectué la division invalide ainsi que la ligne où nous reraise l'exception.

89
répondu Ben 2015-12-29 07:46:23
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

Impressions:

There is a problem: invalid literal for int() with base 10: 'a'
5
répondu eumiro 2015-12-29 07:44:30

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 le tuple args à la place? Je pense que l'avantage possible est que vous pouvez laisser le message d'erreur original seul pour les cas où l'analyse de cette chaîne est nécessaire; et vous pouvez ajouter plusieurs éléments au tuple si votre gestion des erreurs personnalisée produit plusieurs messages ou codes d'erreur, pour les cas où le traceback serait analysé par programme (comme via un système outil de surveillance).

## 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')

Pouvez-vous voir un inconvénient à cette approche?

5
répondu Chris Johnson 2017-10-30 13:09:13

C'est la fonction que j'utilise pour modifier le message d'exception dans Python 2.7 et 3.x tout en préservant le traceback d'origine. Il exige six

def reraise_modify(caught_exc, append_msg, prepend=False):
    """Append message to exception while preserving attributes.

    Preserves exception class, and exception traceback.

    Note:
        This function needs to be called inside an except because
        `sys.exc_info()` requires the exception context.

    Args:
        caught_exc(Exception): The caught exception object
        append_msg(str): The message to append to the caught exception
        prepend(bool): If True prepend the message to args instead of appending

    Returns:
        None

    Side Effects:
        Re-raises the exception with the preserved data / trace but
        modified message
    """
    ExceptClass = type(caught_exc)
    # Keep old traceback
    traceback = sys.exc_info()[2]
    if not caught_exc.args:
        # If no args, create our own tuple
        arg_list = [append_msg]
    else:
        # Take the last arg
        # If it is a string
        # append your message.
        # Otherwise append it to the
        # arg list(Not as pretty)
        arg_list = list(caught_exc.args[:-1])
        last_arg = caught_exc.args[-1]
        if isinstance(last_arg, str):
            if prepend:
                arg_list.append(append_msg + last_arg)
            else:
                arg_list.append(last_arg + append_msg)
        else:
            arg_list += [last_arg, append_msg]
    caught_exc.args = tuple(arg_list)
    six.reraise(ExceptClass,
                caught_exc,
                traceback)
2
répondu Bryce Guinta 2016-08-26 15:52:31

Ce modèle de code devrait vous permettre de déclencher une exception avec un message personnalisé.

try:
     raise ValueError
except ValueError as err:
    raise type(err)("my message")
0
répondu Ruggero Turra 2012-06-12 14:27:22

La réponse actuelle n'a pas bien fonctionné pour moi, si l'exception n'est pas re-Attrapée, le message ajouté n'est pas affiché.

Mais faire comme ci-dessous conserve la trace et montre le message ajouté indépendamment du fait que l'exception soit interceptée ou non.

try:
  raise ValueError("Original message")
except ValueError as err:
  t, v, tb = sys.exc_info()
  raise t, ValueError(err.message + " Appended Info"), tb

(j'ai utilisé Python 2.7, Je ne l'ai pas essayé en Python 3)

0
répondu Zitrax 2015-07-01 07:37:33

Les exceptions intégrées Python 3 ont le champ strerror:

except ValueError as err:
  err.strerror = "New error message"
  raise err
0
répondu user3761308 2017-09-29 13:27:26

Déclenchez la nouvelle exception avec votre message d'erreur en utilisant

raise Exception('your error message')

Ou

raise ValueError('your error message')

Dans l'endroit où vous voulez le soulever ou attacher (remplacer) un message d'erreur dans l'exception actuelle en utilisant 'from':

except ValueError as e:
  raise ValueError('your message') from e
0
répondu Alexey Antonenko 2018-03-20 09:22:59

Si vous voulez coutume, le type d'erreur, une chose simple que vous pouvez faire est de définir une classe d'erreur basé sur ValueError.

-2
répondu igni 2012-02-06 08:16:26