当 Python 3 中已经存在异常时引发异常

新手上路,请多包涵

当在以下代码中引发第二个( B A )会发生什么?

 class A(Exception): pass
class B(Exception): pass

try:
    try:
        raise A('first')
    finally:
        raise B('second')
except X as c:
    print(c)

如果运行 X = A 我得到:

追溯(最近一次通话):
  文件“raising_more_exceptions.py”,第 6 行,在
    提高 A('第一')
__main__.A: 首先

在处理上述异常的过程中,又出现了一个异常:

追溯(最近一次通话):
  文件“raising_more_exceptions.py”,第 8 行,在
    提高 B('第二个')
__main__.B: 第二个

但是如果 X = B 我得到:

第二

问题

  1. 我的第一个例外去哪儿了?
  2. 为什么只能捕获最外层的异常?
  3. 如何剥离最外层的异常并重新引发较早的异常?

更新0

这个问题专门针对 Python 3,因为它的异常处理与 Python 2 完全不同。

原文由 Matt Joiner 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 723
2 个回答

“导致”异常在您的最后一个异常处理程序中作为 c.__context__ 可用。考虑您的第二个示例,其中 X = B (在下面的示例中将 --- 替换为 X B

 try:
    try:
        raise A('first')
    finally:
        raise B('second')
except B as c:
    print(repr(c))
    print(repr(c.__context__))

这将输出:

 B('second')
A('first')

请注意 c.__context__ 指向 A('first') ,这是第一个异常发生的地方。

Python 正在使用此信息来呈现更有用的回溯。在 Python 2.x 下,原始异常将丢失,这仅适用于 Python 3。

通常你会使用它来抛出一个一致的异常,同时仍然保持原始异常的可访问性(虽然它从异常处理程序自动发生是非常酷的,但我不知道!):

 try:
    do_something_involving_http()
except (URLError, socket.timeout) as ex:
    raise MyError('Network error') from ex

更多信息(以及您可以做的其他一些非常有用的事情)在这里: http ://docs.python.org/3.3/library/exceptions.html

原文由 Daniel 发布,翻译遵循 CC BY-SA 4.0 许可协议

回答问题 3,您可以使用:

 raise B('second') from None

这将删除异常 A 回溯。

 Traceback (most recent call last):
  File "raising_more_exceptions.py", line 8, in
    raise B('second')
__main__.B: second

原文由 Frederico Martins 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题