一、异常概述
没有人能保证自己不犯错,而对于开发人员来说,又需要预知所有的可能性,让程序能够正常运行,为了解决这样的矛盾,就产生了异常这种说法,异常是程序在运行过程中发生由于外部问题(如硬件错误、输入错误)等导致的程序异常事件。
二、异常处理机制
1、使用try…except捕获异常
这种机制是将程序运行的代码放到try的代码空间中,如若在执行时产生了异常,则在except中进行处理。
try:
except(Error1,Error2...) as e:
alert 输入不合法
goto retry
这个过程中涉及两个部分: 引发异常:在执行try块的业务代码时,出现了异常,系统会自动产生一个异常对象,并将这个对象交给Python解释器,这个过程就叫引发异常。 捕获异常:当Python解释器收到异常对象时,会寻找能处理异常对象的except块,若找到合适的块,则把异常对象交给except块处理,若找不到,则程序终止。
2、异常捕获流程
需要注意的是,虽然在try之后可以有多个except块,但是Python解释器只会选择与try模块产生的异常相匹配的except块来处理异常。每产生一次异常只会有一个except块来处理异常,注意我们说的是每产生一次异常,如果在try中有循环且使用了continue语句继续循环,则可能导致多个except被执行。
3、异常类的继承体系
关于不同的异常,Python是有不同的处理对象的,异常对象有继承关系,如下。 我们可以看到,所有的异常类都是从BaseException派生而来,但是,有的时候我们需要在异常定义属于自己的提醒标志,这个时候就需要自定义异常类,我们此时应该通过Exception派生。 常见的异常: 1、如果在运行程序时输入的参数不够,将会发生索引错误, Python 将调用 IndexError 对应except 块处理该异常。 2、如果在运行程序时,发生数值错误, Python 将调用ValueError 对应的 except 块处理该异常。 3、如果在运行时发生除0错误, Python 将调用 Arithmetic Error对应 except 理该异常。 4、如果在程序运行时出现其他异常,该异常对象总是Exception 类或其子类的实例, Python将调用 Exception 对应 except 块处理该异常。 注意:我们在进行异常捕获时,应该把父类异常的except块放在子类except块的后面,即先处理小异常后处理大异常。
4、多异常捕获
我们可以想一下,如果产生不同的异常时,我们想要用同样的处理方式处理异常,难道需要重复多次写针对每个异常的代码吗?这样一定使代码很臃肿,那么改如何处理这种情况呢?这里就用到了多异常捕获,也就是说,我们可以主动的把一些类异常归到一块,用一个处理方式。举例如下:
try:
except (IndexError,ValueError,ArithmeticError):
print("程序发生了数组越界,数字格式异常,算术异常之一")
except:
print("未知异常")
except (IndexError,ValueError,ArithmeticError)表示此异常捕获操作可以同时捕获这三种异常,对应的操作都是一样的。 最后的except操作事实上可以用来捕获所有异常,就像上面提到的,我们会把这种父类异常放在所有子类异常的后面。
5、捕获异常信息
我们可以通过异常处理对产生的异常做一些操作,那么如果遇到我们不熟悉的异常并且使用except捕获后,我们如何知道具体的异常信息呢? 所有的异常对象都包含了这样几个属性和方法,方便我们进行异常信息的查询:
- args:属性,返回异常的错误编号和描述字符串
- errno:属性,返回异常的错误编号
- strerror:属性,返回异常的描述字符串
- with_traceback():方法,处理异常的传播轨迹信息
那么具体的代码该如何写呢?我们举个栗子:
def foo():
try:
except Exception as e:
print(e.args)
print(e.errno)
print(e,strerror)
因此,由栗子可知,我们只需要在异常类后使用as关键字再加上异常变量即可。
6、使用finally回收资源
当程序在try里打开了一些物理资源必须被回收时(如数据库连接,网盘连接,磁盘文件等)这些物理资源必须被显示回收,此时我们就用到了finally关键字。 不管try和except中发生了什么,哪怕是使用了return,除一种特殊情况外(在异常处理的except块中使用了os._exit(1)),finally块总是会被执行,且是最后执行。
try:
except:
finally:
注意 1、try是必须有的代码块,而except和finally是可选的,但是二者必须有其一,若二者同时存在,则finally在最后。 2、尽量避免在finally块里使用return和raise等导致方法终止的语句,否则try和except中的部分代码(含有return和raise的代码)无法执行。
当程序执行try、except语句时遇到了return或raise,两个语句都会使该方法结束,但是不会立刻结束,而是去寻找finally语句执行,若没有找到finally,程序立即执行return或raise语句,方法中止;如果找到了finally语句,程序在finally语句执行结束后才会回去执行return或raise语句,但若此时,finally语句块里也有return或raise等导致程序终止的方法,程序便不会回到try、except中里的return或raise了。
三、使用raise引发异常
我们之前提到的异常都是程序在执行过程中出现问题系统自动引发的异常,其实Python也可以允许程序自己引发异常,这便是通过raise完成的。用法如下:
- 单独一个raise,引发当前语句上下文中捕获的异常(比如在except块中),或默认引发RuntimeError
- raise异常类,raise后带一个异常类,该语句引发指定异常类的默认实例。
- raise异常对象,引发指定的异常对象。
注意 raise语句每次只能引发一个异常实例。
|