Exception Handling()异常处理

python有许多内置异常。比如我们常见的TypeError, AttributeError, ValueError等等。 实际上所有的异常都源自一个基类BaseException。 注意并不是Exception类。我们一般在异常处理时捕获的称之为Concrete exceptions,用Exception可以捕获所有这些 Concrete exceptions。
各种异常并不是毫无关系的,有些异常是有继承关系的。 比如ModuleNotFoundError是ImportError的子类。 except子句中使用ImportError可以同时捕获ImportError和MoudleNotFoundError这两种异常。

但像Syntax Error这种异常是语法错误,python解释器会立即抛出,根本不会运行到我们的try … catch语句里。
下面的示例是一个语法错误

while True print('Hello world')
  File "<stdin>", line 1
    while True print('Hello world')
               ^^^^^
SyntaxError: invalid syntax

try … except 语句进行异常捕获和处理。

try:
    x = int('abc')
except ValueError:
    print("Oops!  That was no valid number.  Try again...")

但如果except里没对捕获到的异常类型做处理,只异常会继续抛出。

try:
    x = int('abc')
except NameError:
    print("处理一个NameError")

运行结果:

Traceback (most recent call last):
  File "F:\RolandWork\PythonProjects\studyPython\forTest.py", line 2, in <module>
    x = int('abc')
        ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'abc'

except子句可以捕获多种异常。Exception代表所有类型异常。 要想引用异常,使用as语句,将异常实例存储到变量中。

try:
    x = int('abc')
except NameError:
    print("处理一个NameError")
except AttributeError:
    print("处理一个ValueError")
except Exception as e:
    print(f"处理一个{type(e)}")

输出结果:
处理一个<class 'ValueError'>

还可以用元组来同时处理多种异常。

try:
    x = int('abc')
except (NameError, AttributeError, ValueError) as e:
    print(f"处理一个{type(e)}")

输出结果:
处理一个<class 'ValueError'>

有些异常之间存在继承关系,比如except子句使用ImportError可以捕获ModuleNotFoundError:

try:
    print('do something before error')
    raise ModuleNotFoundError
except ImportError as e:
    print(f'got ImportError: {type(e)}')

输出结果:

do something before error
got ImportError: <class 'ModuleNotFoundError'>

下面演示一下自定义异常,及其继承关系的用法。

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
C
D

异常的except子句里的顺序也重要,一般我们会先处理具体的异常,然后处理一般的异常。因为一旦走到一个异常类型分支,就不会再处理后面的except子句。
比如我们将上面的例子中的except子句的顺序做下调整,将B放在上面,由于B是C和D的基类,所以异常都在except B这里处理了,不会执行后面的except子句。

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 D:
        print("D")
    except C:
        print("C")

输出结果如下:

B
B
B

当我们使用raise加一个Error类时,其实python会自动将其实例化成一个异常实例。 即raise ModuleNotFoundError 等价于 raise ModuleNotFoundError(),并且通常异常类型都至少有一个参数用来实例化异常消息。

try:
    print('do something before error')
    raise ModuleNotFoundError("some module not found")
except ImportError as e:
    print(f'got ImportError: {e}')

输出结果:

do something before error
got ImportError: some module not found

其实在异常内部有个args属性,里面存储了异常的信息。比如我们主动抛出的异常时加的描述性信息。具体到不同的异常时,args属性数量可能不同。python的内置异常都在其__str__方法里帮我们实现了对args属性里内容的输出,所以我们直接print(e)时就能看到这些属性内容。

try:
    raise Exception('spam', 'eggs')
except Exception as inst:
    print(type(inst))    # the exception type
    print(inst.args)     # arguments stored in .args
    print(inst)          # __str__ allows args to be printed directly,
                         # but may be overridden in exception subclasses
    x, y = inst.args     # unpack args
    print('x =', x)
    print('y =', y)

输出结果:

<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

来源链接:https://www.cnblogs.com/rolandhe/p/18685710

请登录后发表评论

    没有回复内容