我对python异常有疑问。 下面的代码取自python文档,我一度感到困惑。如果有人可以帮助,将不胜感激。 在这里,此代码将输出显示为:
B C D
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
如果我更改了部分代码,例如以下代码: 输出将是:
B B B
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except B:
print("B")
except C:
print("C")
except D:
print("D")
当我运行此代码而没有try块时,如下所示:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
raise cls()
这里的输出是:
Traceback (most recent call last):
File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
raise cls()
B
下面的代码为silmilary:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [C,B, D]:
raise cls()
输出是这个
Traceback (most recent call last):
File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
raise cls()
C
我感到困惑是因为,如果我分别运行此代码,那么它将给出B或C或D的输出 那么为什么在我的第二个代码段中将输出显示为
B
B
B
即使为所有3个B,C,D类都定义了
答案 0 :(得分:2)
except子句中的类与异常兼容(如果符合) 相同的类或基类
因此给出了代码:
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
可以简化为以下内容:
for cls in [B, C, D]:
foo = cls()
if isinstance(foo, D):
print("D")
elif isinstance(foo, C):
print("C")
elif isinstance(foo, B):
print("B")
然后您的修改将变成:
for cls in [B, C, D]:
foo = cls()
if isinstance(foo, B):
print("B")
elif isinstance(foo, C):
print("C")
elif isinstance(foo, D):
print("D")
因此,无论foo
是B
,C
还是D
的实例,它都会满足第一种情况,因为isinstance
会产生True
也可以用于子类的实例。
答案 1 :(得分:1)
由于B
是C
和D
的超类,因此您的第二个版本将始终对except
使用第一个B
块。因为Python运行时将从顶部到底部搜索匹配的except
块。如果异常是except
块中类的实例,则except
块将匹配。例如,如果您抛出一个实例C
,则此块将匹配,因为C()
(也是)B
的实例。
根据经验,except
语句必须从最具体的条件减少到最一般的条件,例如e。 g。:
try:
throw ...
except D: # the most specific class
print("D")
except C: # is more specific than B but less than D
print("C")
except B: # the most general class in your hierarchy
print("B")
except BaseException as e: the most general exception class
print(e.__class__.__name__)
答案 2 :(得分:0)
首先让我们了解此代码示例中涉及的类层次结构
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
B->基类
C->继承自B
D->从C继承,C->从B继承
因此D->从B和C继承
对于不同的例外情况,一条try语句可能具有多个except子句。但是最多只能执行一个除外子句
除非您正在捕获引发的异常,否则基类被赋予了优先捕获的权限。即,当继承异常类时,except
中的优先级将赋予BASE类(在您的代码中,其优先级为B
类)。
现在是第一种情况:
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
Iteration 1
:
元素:B
第一个控件检查except D
,因为它既不是基类也不是与引发的类匹配的类,则控件将移至except C
,最后将执行except B
,从而进行打印B
。
Iteration 2
:
元素:C
第一个控件检查except D
,因为它既不是基类也不是与引发的类匹配的类,则控件将移至except C
并执行except C
,从而输出{{1 }}
C
:
元素:D
第一个控件检查Iteration 3
是匹配的类,然后控件将
执行except D
,从而打印except D
现在考虑第二种情况:
D
这里for cls in [B, C, D]:
try:
raise cls()
except B:
print("B")
except C:
print("C")
except D:
print("D")
是类B
和C
的基类,因此当您在除外堆栈的顶部写入D
时,控件不会转到后续的{ {1}}和except B
。因此,对于for循环的每次迭代,它都将输出打印为except C
。