使用类

时间:2018-10-19 10:45:46

标签: python python-3.x exception-handling

我对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类都定义了

3 个答案:

答案 0 :(得分:2)

Python's documentation说:

  

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

因此,无论fooBC还是D的实例,它都会满足第一种情况,因为isinstance会产生True也可以用于子类的实例。

答案 1 :(得分:1)

由于BCD的超类,因此您的第二个版本将始终对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") 是类BC的基类,因此当您在除外堆栈的顶部写入D时,控件不会转到后续的{ {1}}和except B。因此,对于for循环的每次迭代,它都将输出打印为except C