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

iibxawm4  于 2023-05-02  发布在  Python
关注(0)|答案(5)|浏览(187)

在下面的代码中,当第二个异常(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完全不同。

0vvn1miw

0vvn1miw1#

回答问题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
zqry0prt

zqry0prt2#

'causing'异常在最后一个异常处理程序中以c.__context__的形式提供。考虑你的第二个例子,其中X = B(在下面的例子中用B替换X):

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

qacovj5a

qacovj5a3#

Python的异常处理一次只处理一个异常。但是,异常对象和其他对象一样,也要遵守相同的变量规则和垃圾回收。因此,如果您将异常对象保存在某个变量中,您可以稍后处理它,即使引发另一个异常。
在你的例子中,当在“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

如您所见,现在可以访问原始异常。

f8rj6qna

f8rj6qna4#

我相信回答你的问题的所有成分都已经在现有的答案中。让我合并和阐述。
让我重复一下您的问题的代码,以提供行号引用:
所以回答你的问题:
1.我的第一个例外在哪里?
第一个异常A在第6行中抛出。第7行中的finally子句 alwaystry块(第5-6行)离开后立即执行,无论它是因为成功完成还是因为引发异常而离开。在执行finally子句时,第8行引发另一个异常B。正如Lennart和Ignazio所指出的,只有一个例外,即最近提出的例外,可以跟踪。因此,一旦引发B,整个try块(第4-8行)就会退出,如果B匹配(如果XB),则第9行中的except语句会捕获异常B
1.为什么只有最外层的异常是可捕获的?
希望这一点从我对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)

输出为:

('second', A('first',))

1.如何剥离最外面的异常并重新引发前面的异常?
在Lennart的例子中,这个问题的解决方案是except A as e行,其中内部/下部/第一个异常被捕获并存储在变量e中。
作为一个关于何时捕获异常、何时忽略异常以及何时重新引发异常的一般直觉,this question and Alex Martelli's answer可能会有所帮助。

9bfwbjaz

9bfwbjaz5#

1.它被扔掉了。
1.每个线程一次只能有一个异常处于“活动”状态。
1.你不能,除非你以某种方式将前面的异常封装在后面的异常中。

相关问题