一、异常
当检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是异常, 也就是我们常说的BUG,那BUG是怎么由来的呢?
例如:
print(1/0)
我们在小学的时候就知道0不能作除数,运行这条代码,程序不仅无法执行还会报错,零除法错误就是一种异常。
二、异常处理
异常实际上就是一种错误,我们写程序出错误是一件很正常的事情,关键在于发现错误、解决错误。我们要做的,不是要求程序完美, 而是在力所能及的范围内,对可能出现的bug,进行提前准备、提前处理,这种行为叫做异常处理(捕获异常)。
在之前的学习中, 我们所有的程序遇到BUG就会出现整个程序因为一个BUG停止运行的情况, 也就是整个程序直接奔溃。但是在实际工作中, 我们不能因为一个小的BUG就让整个程序全部奔溃, 我们希望的是:对BUG进行提醒后整个程序继续运行。那我们就需要捕获异常:提前假设某处会出现异常,做好提前准备,当真的出现异常的时候,可以有相应的解决方案。
2.1捕获常规异常
语法:
try:
可能发生错误的代码
except:
如果出现异常执行的代码
我们在文件一节学习了open函数——http://t.csdnimg.cn/jVDYK
- 用open函数以只读模式‘r’打开一个文件,如果文件不存在,运行后会报错。
- 用open函数以写入模式‘w’打开一个文件,如果文件不存在,创建新文件进行写入。
假设我们不知道文件test.txt是否存在,我们把以只读模式打开test.txt作为可能发生错误的代码,把以写入模式打开test.txt作为如果出现异常执行的代码。
try:
f = open('test.txt', 'r', encoding='UTF-8')
print("文件test.txt存在")
except:
f = open('test.txt', 'w', encoding='UTF-8')
print("文件test.txt不存在,创建")
输出:
文件test.txt不存在,创建
2.2捕获指定异常
语法:
try:
可能发生错误的代码
except 错误种类 as e:
如果出现异常执行的代码
如果我们打印输出一个未定义的变量
print(ret)
运行起来会报错:
我们捕捉这种特定的异常NameError,代码如下:
try:
print(ret)
except NameError as e:
print("变量名称未定义错误")
输出:
变量名称未定义错误
我们再看另一个代码示例,捕捉这种特定的异常FileNotFoundError:
try:
f = open('test.txt', 'r', encoding='UTF-8')
except FileNotFoundError as e:
print("文件不存在错误")
输出:
文件不存在错误
如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
try:
f = open('test.txt', 'r', encoding='UTF-8')
except NameError as e:
print("文件不存在错误")
出现的代码异常是文件不存在错误,捕获的异常类型是变量名称未定义错误,两者不一致,无法捕捉,运行会报错。
2.3捕获多个异常
当捕获多个异常时,可以把要捕获的异常类型的名字,放到except 后,以元组的方式进行书写。
代码示例:
try:
print(1/0)
except (NameError,FileNotFoundError,ZeroDivisionError) as e:
print('变量名称未定义错误/文件不存在错误/零除法错误')
输出:
变量名称未定义错误/文件不存在错误/零除法错误
代码示例:
try:
f = open('test.txt', 'r', encoding='UTF-8')
except (NameError,FileNotFoundError,ZeroDivisionError) as e:
print('变量名称未定义错误/文件不存在错误/零除法错误')
输出:
变量名称未定义错误/文件不存在错误/零除法错误
代码示例:
try:
print(ret)
except (NameError,FileNotFoundError,ZeroDivisionError) as e:
print('变量名称未定义错误/文件不存在错误/零除法错误')
输出:
变量名称未定义错误/文件不存在错误/零除法错误
如何在捕获异常的同时准确地输出描述信息呢?
输出变量e即可,代码示例:
try:
print(ret)
except (NameError,FileNotFoundError,ZeroDivisionError) as e:
print(e)
输出:
name 'ret' is not defined
2.4捕获所有异常
捕获所有异常有两种方式,第一种就是捕获常规异常的方式,第二种如下所示:
语法:
try:
可能发生错误的代码
except Exception as e:
如果出现异常执行的代码
方式一:
try:
print(ret)
except:
print('errno')
输出:
errno
方式二:
try:
print(ret)
except Exception as e:
print(e)
输出:
name 'ret' is not defined
三、异常处理中的else与finally
3.1异常处理中的else
语法:
try:
可能发生错误的代码
except:
如果出现异常执行的代码
else:
如果没有异常要执行的代码
代码示例:
try:
print(5/1)
except:
print('errno')
else:
print('perfect')
输出:
5.0
perfect
3.2异常处理中的finally
语法:
try:
可能发生错误的代码
except:
如果出现异常执行的代码
finally:
无论是否异常都要执行的代码
代码示例:
try:
print(5/0)
except:
print('errno')
finally:
print('阳光总在风雨后')
输出:
errno
阳光总在风雨后
代码示例:
try:
print(5/1)
except:
print('errno')
else:
print('perfect')
finally:
print('阳光总在风雨后')
输出:
5.0
perfect
阳光总在风雨后
注意:异常处理中的else与finally都是可选的,可以写也可以不写。
四、异常的传递性
请先看这个函数多层调用的例子:
def func1():
ret=1/0
print(ret)
def func2():
print('func2的开始')
func1()
print('func2的结束')
def main():
func2()
main()
运行后报错:
使用异常处理后:
def func1():
ret=1/0
print(ret)
def func2():
print('func2的开始')
func1()
print('func2的结束')
def main():
try:
func2()
except Exception as e:
print(e)
main()
输出:
func2的开始
division by zero
请看程序执行的顺序:
我们通过输出结果,可以了解到:
这说明异常不是必须在真正出现异常的地方被捕获,可以在高的层级被捕获,因为异常是可以传递的。
利用异常具有传递性的特点, 当我们想要保证程序不会因为异常崩溃的时候, 就可以在main函数中设置异常捕获, 由于无论在整个程序哪里发生异常, 最终都会传递到main函数中, 这样就可以确保所有的异常都会被捕获。