python:异常处理
1、异常的概念
python程序运行时,如果python解释器遇到了一个错误,那么就停止程序的运行,并提示一些错误信息,那么这就是异常。而程序停止运行并在控制台弹出红色的提示信息,这个行为通常称之为“抛出异常”
例如:
a = [1, 2, 3]
# 该列表的索引从0-2
# 从语法上讲这个输出并没有错
print(a[3])
# 而输出的是索引为3,那么压根就没有,所以一定会抛出索引超出界限的错误
抛出异常:
2、异常捕获
在开发过程中,如果对某一块代码的运行结果不确定,那么就可以使用基本的异常捕获语法来测试。
语法格式:
"""
注意:
【1】当try块中的代码块没有错误,那么将直接执行完毕,而不会进入except中
【2】而try块中的代码执行时发现错误,那么将停止执行try块中的代码,直接进入except,执行except中的代码
"""
try:
# 尝试执行的代码块
except:
# 出现错误的处理代码
例子:
# 要求让用户输入整数
try:
# 如果用户输入的不是整数,那么将直接跳出try块,去执行except中的代码
age = int(input("请输入你的年龄:"))
except:
print("您输入的值错误,只能输入整数!")
3、指定错误类型捕获
如果在开发的过程中知道会抛出怎样的异常那么我们就不会去使用上边的格式,而是使用指定的异常类型,而这些指定异常就是异常类,就是咱们运行程序抛出异常最后一行的冒号:前边的xxxError就是异常类。如下图所示,皆为python内置的标准异常:
python标准异常:
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
其实except关键字后边是可以添加参数,这个参数可以是一个也可以是多个,如下代码所示:
语法格式;
1、捕获单个指定异常:
try:
num = 0
print(1/num)
except ZeroDivisionError:
print("除数不为0")
2、捕获多个指定异常:
try:
print(1 + "哈哈")
num = 0
print(1 / num)
# 这括号里边类似于元组的形式
except (ZeroDivisionError,TypeError):
print("除数不为0")
print("类型错误!")
# 注意:如果还要异常,但是你没有写出指定的错误类型,那么也会抛出异常
# 并且,异常类型不对称,那么也会抛出异常
4、使用多个except捕获指定异常:
try:
print(1 + "哈哈")
num = 0
print(1 / num)
except ZeroDivisionError:
print("除数不为0")
except TypeError:
print("类型错误!")
4、异常提示信息
那么,如何拿出异常类的提示信息呢?我们可以使用as变量,将其返回的值输出即可。
格式:
try:
# 尝试的代码块
except (error1,error2……)as rest:
print(rest)
例子:
try:
print(1 + "哈哈")
num = 0
print(1 / num)
except ZeroDivisionError as error1:
print(error1)
except TypeError as error2:
print(error2)
5、异常类
上面提到,抛出异常冒号:之前的就是异常类,而这些标准异常类五花八门,有时候我们根本不知道,那么我们就可以将这些指定的异常类替换成Exception,因为Exception也是一个异常类,但是它是所有异常类的父类,一切的标准异常类都继承自Exception类,所有我们就可以使用Exception类通过as变量来获取到每一个异常子类的异常提示信息,上边在指定错误类型捕获已经列出了pytyhon内置的标准异常类,下面直接看例子。
例子:
try:
print(1 + "哈哈")
num = 0
print(1 / num)
except Exception as error1 :
print(error1)
6、异常捕获完整语法
try:
# 尝试执行的代码
ecxept:
# 发现异常时执行的代码
else:
# 没有异常时执行的代码
finall:
# 不管有没有异常都要执行的代码
例子:
# while循环用于当用户输入的数字或者字符不能转换为整数时重新输入
while True:
try:
age = int(input("请输入你的年龄:"))
except Exception as result:
print(result)
else:
print("年龄输入无误!")
print("注册成功!")
# 带没有异常后,就直接跳出循环,不去执行finally
break
finally:
# 只有当用户输入错误时执行,因为上变有一个break
print("年龄格式输入错误,请重新输入:")
7、异常传递
(1)try嵌套中
import time
# 外try
try:
# 本来就没有这个文件,那么一定会报错
# f = open("test.txt")
# 内try
try:
# 用于读取文件
while True:
# 每次读取一行
content = f.readline()
# 当长度为0就说明读取完成
if len(content) == 0:
# 就跳出循环
break
# 如果每次读取到数据
else:
# 就停留2秒
time.sleep(2)
# 然后输出
print(content)
# 当内try执行,不管有没有异常都要关闭文件
finally:
print("关闭文件")
f.close()
# 外try异常处理
except:
print("没有这个文件")
注意:
1、没有该文件,却已默认的’r’方式打开文件,那么一定会出现异常,所以就不会到内try里边去,所以就不会出现异常传递现象
2、但是,当把以’r’方式打开文件的代码注释,那么就会进入内try中,并且发现异常,输出内finally里边的语句,当看到关闭文件又出现异常,所以就会将两处错误全部传递给外try,那么外try捕获到异常,就执行except中的代码。所以这个时候就出现了异常传递现象
(2)函数嵌套调用中
# 让用户输入一个值,并转换为整数,并输出返回这个值
def func1():
i = int(input("请输入一个整数"))
print(f"您输入的是数字是{i}")
return i
# func2调用func1,并返回一个用户输入的值
def func2():
return func1()
# func3调用func2,并接收一个返回的值,最后输出
def func3():
x = func2()
print(x)
# 调用func3
func3()
注意:
1、在这种函数嵌套调用的程序中,如果都没有做异常捕获和处理,那么将会出现连锁反应,就是异常传递,三个函数都报错,准确的说是四处,func3调用先出现错误,然后是func3内的func2调用出现错误,接着是func2内的func1调用错误,最后是func1的第一行出现错误。
2、当用户输入整数,那么程序正常运行,但当输出字符、小数,那么将产生异常传递现象,所以在实际开发中为了防止异常传递到main函数中,我们通常会到某些函数或者内部做相应的异常捕获和处理
8、抛出异常
python使用raise关键字,抛出一个指定异常,或者说raise用于主动抛出异常,前提需要一个自定义异常类
语法格式:
raise Exception异常对象
如图所示:
9、自定义异常类
python中提供了一个Exception异常类
在开发时如果要满足特定业务需求时,需要抛出异常,可以:
(1)创建一个异常类(自定义异常类)
(2)使用raise关键字抛出异常对象
# 自定义异常类,必须继承Exception类,因为它是所以异常类的父类
class AgeInputError(Exception):
def __init__(self,age):
self.age = age
# 当调用函数时,自动返回一段字符串
def __str__(self):
return f"您输入的年龄为:{self.age}岁,年龄必须为整数,并且大于0"
def main():
# 当用户输入错误时重新输入
while True:
# 让用户尝试输入年龄
try:
# 当年龄不能转换为整数,将直接跳到except中输出错误信息
age = int(input("请输入你的年龄:"))
# 当用户输入的年龄小于等于0
if age <= 0:
# 主动抛出异常 并调用异常对象
raise AgeInputError(age)
# 当主动抛出异常后,输出str函数中返回的值
except Exception as result:
print(result)
# 当没有发现异常执行的代码
else:
print("年龄输入正确!")
# 并跳出循环
break
finally:
# 如果执行到finally就说明有异常,那么就提醒用户继续输入
print("请重新输入!")
# 调用主函数
main()