我在我的代码中有这个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 3,检查Ben的答案


将一条消息附加到当前异常并重新引发: (外面的try/except只是为了展示效果)

对于python 2。其中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)

如果err是从ValueError派生的,这也会做正确的事情。例如UnicodeDecodeError。

请注意,您可以添加任何您喜欢的错误。例如err.problematic_array=[1,2,3]。


编辑:@Ducan在注释中指出,上述内容不适用于python 3,因为.message不是ValueError的成员。相反,你可以使用这个(有效的python 2.6或更高版本或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:

根据目的,您还可以选择在自己的变量名下添加额外的信息。对于python2和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

其他回答

上面的解决方案都没有完全满足我的要求,即在错误消息的第一部分添加一些信息,即我希望我的用户首先看到我的自定义消息。

这招对我很管用:

exception_raised = False
try:
    do_something_that_might_raise_an_exception()
except ValueError as e:
    message = str(e)
    exception_raised = True

if exception_raised:
    message_to_prepend = "Custom text"
    raise ValueError(message_to_prepend + message)

我尝试了这个精简版的@RobinL,效果很好:

try:
    do_something_that_might_raise_an_exception()
except ValueError as e:
    raise ValueError(f'Custom text {e}')

上面提出的许多解决方案再次引发异常,这被认为是一种糟糕的做法。像这样简单的东西就可以了

try:
    import settings
except ModuleNotFoundError:
    print("Something meaningfull\n")
    raise 

因此,您将首先打印错误消息,然后引发堆栈跟踪,或者您可以简单地通过sys.exit(1)退出,而根本不显示错误消息。

It seems all the answers are adding info to e.args[0], thereby altering the existing error message. Is there a downside to extending the args tuple instead? I think the possible upside is, you can leave the original error message alone for cases where parsing that string is needed; and you could add multiple elements to the tuple if your custom error handling produced several messages or error codes, for cases where the traceback would be parsed programmatically (like via a system monitoring tool).

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

or

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

你能看出这种方法的缺点吗?

这只适用于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')