淘先锋技术网

首页 1 2 3 4 5 6 7

当第二个(B在下面的代码中引发时,我的第一个异常(A发生了什么?

1

2

3

4

5

6

7

8

9

10class A(Exception): pass

class B(Exception): pass

try:

try:

raise A('first')

finally:

raise B('second')

except X as c:

print(c)

如果用X = A运行,我得到:

1

2

3

4

5

6

7

8

9

10

11Traceback (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我得到:

1second

问题

我的第一个例外是什么?

为什么只有最外层的异常是可捕获的?

如何剥离最外层的异常并重新评估早期的异常?

更新0

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

答案似乎忽略了这样一个事实,即当异常没有被捕获时,我仍然可以得到完整的回溯。请解释一下?

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

1raise B('second') from None

这将删除异常A回溯。

1

2

3

4Traceback (most recent call last):

File"raising_more_exceptions.py", line 8, in

raise B('second')

__main__.B: second

谢谢,这解决了我的问题…希望从基类方法中的keyError引发自定义异常。我的列表是一个子类属性,子类对象是动态生成的。默认的keyError跟踪没有说明错误发生在哪个子类中,因此我想抑制它并用更多信息引发新的异常。"把x从"无"中提高"允许我这样做。

如果要保存原始的回溯,可以使用:引发OtherException(…).with_traceback(tb),如docs.python.org/3/library/exceptions.html baseexception中所述。

"引发"异常在上一个异常处理程序中作为C."上下文"提供。python使用这些信息来呈现更有用的回溯。在python 2.x下,原来的异常会丢失,这只适用于python 3。

通常,在保持原始异常可访问的同时,您可以使用它来抛出一个一致的异常(尽管从异常处理程序自动发生非常酷,但我不知道!):

1

2

3

4try:

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

pythons异常处理一次只能处理一个异常。但是,异常对象和其他对象一样受相同的变量规则和垃圾收集的约束。因此,如果将异常对象保存在某个变量中,即使引发了另一个异常,也可以在以后处理它。

在您的例子中,当在"finally"语句中引发异常时,python 3将在第二个异常之前打印出第一个异常的回溯,这样更有用。

更常见的情况是,您希望在显式异常处理期间引发异常。然后您可以在下一个异常中"保存"该异常。只需将其作为参数传入:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15>>> 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

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

你能回答第一部分吗?

@马特:哪儿也去不了。不过,我确实意识到我有一个脑残,并更新了我的答案。

在教义中如何处理这种情况?

或者可以使用raise x from y?

如果您只支持python 3,是的。这现在是合理的,但在2011年是不合理的。

我相信回答你问题的所有要素都已经在现有答案中了。让我结合并详细阐述。

让我重复您的问题代码,以提供行号参考:

1

2

3

4

5

6

7

8

9

101 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)

所以要回答你的问题:

我的第一个例外是什么?

您的第一个异常A出现在第6行。第7行中的finally条款总是在try块(第5-6行)离开后立即执行,不管是因为成功完成还是因为引发的异常而离开。在执行finally条款时,第8行又提出了一个例外B。正如伦纳德和伊格纳齐奥所指出的,只有一个例外,即最近被提出的例外,可以被跟踪。因此,一旦B被提出,整个try区块(第4-8行)就退出,如果与之匹配(如果X是B的话),第9行的except语句就会捕获异常B。

为什么只有最外层的异常是可捕获的?

希望我对1的解释现在已经清楚了。不过,您可以捕获内部/下部/第一个异常。要合并Lennart的回答,稍微修改一下,下面介绍如何同时捕捉这两个问题:

1

2

3

4

5

6

7

8

9class 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)

输出是:

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

如何剥离最外层的异常并重新评估早期的异常?

在Lennart的例子中,这个问题的解决方案是行except A as e,在该行内/下/第一个异常被捕获并存储在变量e中。

作为一种直觉一般的感觉,什么时候抓住例外,什么时候忽视它们,什么时候再提出,也许这个问题和亚历克斯·马泰利的回答有帮助。

它被扔掉了。

每个线程一次只能有一个异常是"活动的"。

除非您以某种方式将前面的异常封装到后面的异常中,否则您不能这样做。

如果它被抛出了,为什么在没有捕获异常的情况下我会得到完整的回溯呢?

因为您用来运行脚本的工具安装了一个全局异常处理程序,并且它注意到了双重异常。

什么工具…?

我现在看到了,python 3.x有不同的行为。正是口译员自己抓住了它。在2.x中,第一个异常被静默删除。