在下面的代码中,当第二个异常(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
,则得到:
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
我在想:
1.我的第一个例外在哪里?
1.为什么只有最外层的异常是可捕获的?
1.如何剥离最外面的异常并重新引发前面的异常?
这个问题专门针对Python 3,因为它的异常处理与Python 2完全不同。
5条答案
按热度按时间0vvn1miw1#
回答问题3,您可以用途:
这将删除异常
A
追溯。zqry0prt2#
'causing'异常在最后一个异常处理程序中以
c.__context__
的形式提供。考虑你的第二个例子,其中X = B
(在下面的例子中用B
替换X
):这将输出:
请注意,
c.__context__
指向A('first')
,这是第一个异常发生的地方。Python使用这些信息来呈现更有用的回溯。在Python 2下。x原始异常将丢失,这仅适用于Python 3。
通常,您会使用它来抛出一致的异常,同时仍然保持原始异常的可访问性(尽管它非常酷,从异常处理程序自动发生,我不知道!):
更多信息(以及其他一些你可以做的非常有用的事情)在这里:http://docs.python.org/3.3/library/exceptions.html
qacovj5a3#
Python的异常处理一次只处理一个异常。但是,异常对象和其他对象一样,也要遵守相同的变量规则和垃圾回收。因此,如果您将异常对象保存在某个变量中,您可以稍后处理它,即使引发另一个异常。
在你的例子中,当在“finally”语句中引发异常时,Python 3将在第二个异常之前打印出第一个异常的回溯,这更有帮助。
更常见的情况是,您希望在显式异常处理期间引发异常。然后您可以在下一个异常中“保存”该异常。把它作为一个参数传入:
如您所见,现在可以访问原始异常。
f8rj6qna4#
我相信回答你的问题的所有成分都已经在现有的答案中。让我合并和阐述。
让我重复一下您的问题的代码,以提供行号引用:
所以回答你的问题:
1.我的第一个例外在哪里?
第一个异常
A
在第6行中抛出。第7行中的finally
子句 always 在try
块(第5-6行)离开后立即执行,无论它是因为成功完成还是因为引发异常而离开。在执行finally
子句时,第8行引发另一个异常B
。正如Lennart和Ignazio所指出的,只有一个例外,即最近提出的例外,可以跟踪。因此,一旦引发B
,整个try
块(第4-8行)就会退出,如果B
匹配(如果X
是B
),则第9行中的except
语句会捕获异常B
。1.为什么只有最外层的异常是可捕获的?
希望这一点从我对1的解释中已经清楚了。但是,您可以捕获内部/较低/第一个异常。为了合并Lennart的答案,稍微修改一下,下面是如何捕获两者:
输出为:
1.如何剥离最外面的异常并重新引发前面的异常?
在Lennart的例子中,这个问题的解决方案是
except A as e
行,其中内部/下部/第一个异常被捕获并存储在变量e
中。作为一个关于何时捕获异常、何时忽略异常以及何时重新引发异常的一般直觉,this question and Alex Martelli's answer可能会有所帮助。
9bfwbjaz5#
1.它被扔掉了。
1.每个线程一次只能有一个异常处于“活动”状态。
1.你不能,除非你以某种方式将前面的异常封装在后面的异常中。