我在我的代码中有这个try块:

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

严格地说,我实际上引发了另一个ValueError,而不是do_something…()抛出的ValueError,在这种情况下被称为err。如何将自定义消息附加到错误?我尝试以下代码,但失败,由于错误,ValueError实例,不可调用:

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

当前回答

这是我在Python 2.7和3中用来修改异常消息的函数。X,同时保留原始的回溯。需要6个

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)

其他回答

当前的答案对我来说并不是很好,如果没有重新捕获异常,则不会显示附加的消息。

但是像下面这样做既保持跟踪,又显示附加的消息,不管是否重新捕获异常。

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

(我使用Python 2.7,在Python 3中没有尝试过)

如果你足够幸运只支持python 3。X,这真的变成了一件美丽的事情:)

提高从

我们可以使用raise from链接异常。

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

在这种情况下,调用者将捕获的异常具有引发异常的位置的行号。

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

注意,底部异常只有我们引发异常的堆栈跟踪。调用者仍然可以通过访问他们捕获的异常的__cause__属性来获得原始异常。

with_traceback

或者你可以使用with_traceback。

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

使用这种形式,调用者将捕获的异常具有原始错误发生位置的回溯。

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

注意,底部的异常中有执行无效除法的行,也有重新引发异常的行。

这只适用于Python 3。您可以修改异常的原始参数并添加自己的参数。

异常会记住创建它时使用的参数。我认为这样您就可以修改异常了。

在函数rerraise中,我们在异常的原始参数前加上我们想要的任何新参数(比如消息)。最后,我们在保留回溯历史的同时重新引发异常。

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 exception and preserve the traceback info so that 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()

输出

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')
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

打印:

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

如果你想自定义错误类型,你可以做的一件简单的事情就是基于ValueError定义一个错误类。