Mat*_*ner 38 python exception-handling exception python-3.x
在下面的代码中引发A第二个(B)时,我的第一个异常()会发生什么?
class A(Exception): pass
class B(Exception): pass
try:
try:
raise A('first')
finally:
raise B('second')
except X as c:
print(c)
Run Code Online (Sandbox Code Playgroud)
如果运行X = A我得到:
Traceback (most recent call last):
File "raising_more_exceptions.py", line 6, in
raise A('first')
__main__.A: first
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "raising_more_exceptions.py", line 8, in
raise B('second')
__main__.B: second
但如果X = B我得到:
second
这个问题专门针对Python 3,因为它的异常处理与Python 2完全不同.
Fli*_*pym 21
回答问题3,您可以使用:
raise B('second') from None
Run Code Online (Sandbox Code Playgroud)
这将删除异常A回溯.
Traceback (most recent call last):
File "raising_more_exceptions.py", line 8, in
raise B('second')
__main__.B: second
Run Code Online (Sandbox Code Playgroud)
Dan*_*iel 10
'cause'异常在上一个异常处理程序中以c .__ context__的形式提供.Python正在使用此信息来呈现更有用的回溯.在Python 2.x下,原始异常将丢失,这仅适用于Python 3.
通常你会使用它来抛出一致的异常,同时仍然保持原始异常可访问(尽管从异常处理程序自动发生它非常酷,我不知道!):
try:
do_something_involving_http()
except (URLError, socket.timeout) as ex:
raise MyError('Network error') from ex
Run Code Online (Sandbox Code Playgroud)
这里有更多信息(以及其他一些非常有用的东西):http://docs.python.org/3.3/library/exceptions.html
Pythons异常处理一次只处理一个异常.但是,异常对象与其他所有对象一样受到相同的变量规则和垃圾收集的约束.因此,如果将异常对象保存在某个变量中,您可以稍后处理它,即使引发了另一个异常.
在您的情况下,当在"finally"语句中引发异常时,Python 3将在第二个异常之前打印出第一个异常的回溯,以便更有帮助.
更常见的情况是您希望在显式异常处理期间引发异常.然后,您可以在下一个异常中"保存"异常.只需将其作为参数传递:
>>> class A(Exception):
... pass
...
>>> class B(Exception):
... pass
...
>>> try:
... try:
... raise A('first')
... except A as e:
... raise B('second', e)
... except Exception as c:
... print(c.args[1])
...
first
Run Code Online (Sandbox Code Playgroud)
如您所见,您现在可以访问原始异常.
我相信回答你问题的所有要素都已经存在于现有的答案中.让我结合并详细说明.
让我重复一下你问题的代码,提供行号参考:
1 class A(Exception): pass
2 class B(Exception): pass
3
4 try:
5 try:
6 raise A('first')
7 finally:
8 raise B('second')
9 except X as c:
10 print(c)
Run Code Online (Sandbox Code Playgroud)
那么回答你的问题:
第A6行引发了第一个异常.finally第7 行中的子句总是在try块(第5-6行)被保留后立即执行,无论是否由于成功完成或由于引发异常而离开.在finally执行该条款时,第8行引发了另一个例外B.正如Lennart和Ignazio指出的那样,只有一个例外,即最近被提出的例外,可以被追踪.因此,一旦B引发,整个try块(第4-8行)就会退出,如果匹配(如果是),则第9行中B的except语句将捕获异常.XB
希望现在从我对1的解释中可以清楚地看到这一点.但是你可以捕获内/低/第一个异常.要合并Lennart的答案,略微修改,以下是如何捕捉两者:
class A(Exception): pass
class B(Exception): pass
try:
try:
raise A('first')
except A as e:
raise B('second', e)
except Exception as c:
print(c)
Run Code Online (Sandbox Code Playgroud)
输出是:
('second', A('first',))
Run Code Online (Sandbox Code Playgroud)
在Lennart的例子中,这个问题的解决方案except A as e是捕获内部/下部/第一个异常并存储在变量中的行e.
作为对何时捕捉异常,何时忽略它们以及何时重新加注的一般直觉,也许这个问题和Alex Martelli的答案有所帮助.