Python进阶篇01-错误与异常处理
一、什么是错误与异常
错误
一般指程序编写有误,语法不规范而导致程序无法运行,这样的称为错误;
异常
程序无语法问题,可以正常运行,但在运行过程中出现的错误,例如:值转换错误(int('a'))、除数不能为0等,这样的问题称为异常;
当发生异常时,程序会抛出这个异常并且停止运行,因此为了更快定位问题、避免程序在不需要停止的地方停止允许,我们应该对异常进行恰当的捕获并且抛出,根据实际场景选择是停止运行还是继续往下走其余逻辑。
二、如何捕获并抛出异常
捕获异常的基本格式
在Python中,处理异常会使用try-except语句,这个语句还有两个可选的子句:else和finally,整体基本流程如下:
第一种最基础的格式,try-except
:
try:
statements
except [errortype]:
statements
except [errortype]:
statements
此为Python处理异常的最基本结构:try分支中的语句为可能会出现异常的代码块,except为捕获异常并进行处理的语句--可以有多个,但只会执行一个except分支。except后通常为要处理的预见可能会出现的异常类型,异常类型可以为一个或多个--为多个时使用元组 (RuntimeError, TypeError, NameError) ,最后一个except可以省略异常名称,将异常信息作为意外异常进行打印;
处理流程如下:
- 执行了try分支中的语句,若未触发异常,则将try分支中代码块执行完毕后,代码忽略except分支,继续往下执行。若触发了异常,则执行except分支;
- 触发了异常,执行except分支,通过触发的异常类型来与except后的异常类型来进行匹配,若成功匹配,则执行该except分支下的代码;
第二种,try-except-else
,可选语句else
try:
statements
except ......:
statements
else:
statements
- else语句为可选语句,若写,则需要放在所有的except语句之后,可以理解为:若发生异常--找到相匹配的except分支并执行--相反、未发生异常,则执行else分支;
- else分支用来执行未发生异常时需要继续执行的代码块,我们可以将认为有可能出现异常的代码块放在try分支中,将不太可能出现异常的代码块放在else分支下;
第三种,try-except-finally
,可选语句finally:
try:
statements
except ......:
statements
finally:
statements
- finally语句为可选语句,意为最终,是
try-except-[else]-[finally]
结构中,最终的部分,是无论是否发生异常,都会执行的分支; - 在
try-except-[else]-[finally]
结构中,各子句的顺序需要遵循此顺序; - 如果在try子句中发生了异常(或者在 except 和 else 子句里),但没有被任何except语句捕获,那么这个异常会在执行完 finally 分支后抛出。
assert语句触发异常
- assert断言 语句后跟表达式,当表达式结果为True时,不做任何操作;当表达式结果为False时,触发 AssertionError 异常。
assert 1 == 2
raise语句抛出异常
- raise语句后为一个可选参数;
- 当填写此参数时,此参数必须是一个异常类,也就是 Exception 的子类;
a = 3
b = 0
if b == 0:
raise ZeroDivisionError('除数不能为0')
print(a / b)
- raise语句后若不写参数,则直接抛出当前异常。
try:
a = 3 / 0
except ZeroDivisionError:
print('error!')
raise
-----------
Traceback (most recent call last):
File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 835, in <module>
a = 3 / 0
ZeroDivisionError: division by zero
error!
- raise语句是在可预见有异常发生的情况下,手动抛出某异常,而except语句是捕获异常并进行处理。若except捕获异常后却并没有进行抛出,则可以使用单独的、不添加参数的
raise
语句抛出当前异常;若在except分支中使用raise [ErrorType]
再抛出异常,则会报错During handling of the above exception, another exception occurred
,并且会影响真正需要抛出的异常信息。若在raise抛出的异常中未添加有效的额外错误信息,则此种写法并没有多大意义。
try:
a = 3 / 0
except ZeroDivisionError:
print('error!')
raise ZeroDivisionError('除数不能为0')
-----------
error!
Traceback (most recent call last):
File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 835, in <module>
a = 3 / 0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/lxc/Desktop/codeSpace/myCode/pyCode/all_study_practice/sth_temps.py", line 838, in <module>
raise ZeroDivisionError('除数不能为0')
ZeroDivisionError: 除数不能为0
三、用户自定义异常
- 用户可以通过继承
Exception
类来自定义异常。
class MyError(Exception):
pass
- 如果内置异常已经可以满足需要,建议使用内置异常。
四、常见的异常类型有哪些
- 内置异常的层次结构如下:
BaseException ——所有异常的基类,最基础的异常类
+-- SystemExit ——解释器请求退出
+-- KeyboardInterrupt ——用户中断执行
+-- GeneratorExit ——生成器发生异常来通知退出
+-- Exception ——常规错误的基类
+-- StopIteration ——迭代器没有更多的值
+-- StandardError ——所有内建标准异常的基类
| +-- BufferError
| +-- ArithmeticError ——所有数值计算错误的基类
| | +-- FloatingPointError ——浮点计算错误
| | +-- OverflowError ——数值运算超出最大限制
| | +-- ZeroDivisionError ——除(或取模)0
| +-- AssertionError ——断言失败
| +-- AttributeError ——对象没有这个属性
| +-- EnvironmentError ——操作系统错误的基类
| | +-- IOError ——输入/输出操作失败
| | +-- OSError ——操作系统错误
| | +-- WindowsError (Windows) ——系统调用失败
| | +-- VMSError (VMS)
| +-- EOFError
| +-- ImportError ——导入模块/对象失败
| +-- LookupError ——无效数据查询的基类
| | +-- IndexError ——序列中没有此索引
| | +-- KeyError ——映射中没有这个键
| +-- MemoryError ——内存溢出错误
| +-- NameError ——未声明/初始化对象
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError ——一般的运行时错误
| | +-- NotImplementedError
| +-- SyntaxError ——Python语法错误
| | +-- IndentationError ——缩进错误
| | +-- TabError ——Tab 和空格混用
| +-- SystemError
| +-- TypeError ——对类型无效的操作
| +-- ValueError ——传入无效的参数
| +-- UnicodeError ——Unicode相关的错误
| +-- UnicodeDecodeError ——Unicode解码时的错误
| +-- UnicodeEncodeError ——Unicode编码时的错误
| +-- UnicodeTranslateError ——Unicode转换时的错误
+-- Warning ——警告的基类
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
- 从层级结构上来看,
BaseException
是所有异常的基类,Exception
继承自BaseException
;BaseException
除了包含Exception
外还包含另外三个异常,而这另外三个异常属于更高级别的异常,合理的做法是交给Python解释器进行处理。因此我们在要捕获通用的异常时,最好的做法是使用Exception
来进行匹配。