如何在Python中以自定义消息引发相同的异常?

287 投票
16 回答
210073 浏览
提问于 2025-04-17 12:24

我在代码中有一个 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。我想知道如何给 err 添加一个自定义的消息?我尝试了以下代码,但失败了,因为 err 是一个 ValueError实例,而不是可以调用的东西:

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

16 个回答

18

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

异常会记住它创建时的参数。我想这是为了让你可以修改这个异常。

在函数 reraise 中,我们在异常的原始参数前面加上任何我们想要的新参数(比如一条消息)。最后,我们重新抛出这个异常,同时保留追踪记录。

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

更新:对于Python 3,请查看 Ben的回答

更新2023:我在十多年前写了这个回答,现在有更好的答案。你应该使用Python 3,并参考上面的回答。

原始回答:

要给当前的异常添加一条信息并重新抛出它:
(外面的try/except只是为了展示效果)

对于Python 2.x,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中添加任何你想要的信息。例如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))

编辑2:

根据你的目的,你也可以选择在自己的变量名下添加额外的信息。对于Python 2和Python 3都适用:

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
356

如果你运气好,只需要支持 Python 3.x,那这就真的变得很美妙了 :)

raise from

我们可以使用 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

注意,底部的异常不仅显示了我们进行无效除法的那一行,还显示了我们重新抛出异常的那一行。

撰写回答