目录
1. 使用try...except 捕获异常
2. 异常类的继承
3. 多异常捕获(一个except块可以捕获多种类型的异常)
4. 访问异常信息
5. else块
6. finally回收资源
Python的异常机制主要依靠五个关键字:try、except、else、finally、raise;
try(异常处理中只有try块是必需的) | try关键字后的代码块为程序正常运行代码块(这部分代码可能引发异常) |
except(except块与finally块至少出现一个) | 包含对应异常类型和处理这种异常类型的代码块 |
else | 位于多个except块后,当程序不出现异常时执行else块 |
finally(必须位于所有的except块之后) | finally块用于回收try块里打开的物理资源,finally块总被执行 |
raise | 用于引发一个实际的异常; |
语法结构:
try:
程序运行代码
except Error1:
异常处理代码
except Error2:
异常处理代码
...
except Exception:
可以对所有异常进行处理
1)当try块中的程序运行出现异常时,系统会自动生成一个异常对象,该异常对象会自动提交给Python解释器;
2)当Python解释器接收到异常对象时,会寻找处理该异常对象的except块,如果找到对应的except块,则把该异常对象交给该except块处理;
input_num = input("输入一个数字:")
while input_num :
try:
# 如果输入的数字不是整数,使用int()函数将引发ValueError异常
num = int(input_num)
print("输入的数字为%d"%num)
break
# 该except块将捕获ValueError异常并对该异常进行处理
except ValueError:
# 表示输入的值不是数字时重新输入数字
input_num = input("输入一个数字:")
continue
# 输入一个数字:a
# 输入一个数字:10
# 输入的数字为10
3)如果找不到对应的except块,则运行环境终止,python解释器也将退出;
input_num = input("输入一个数字:")
while input_num :
try:
num = int(input_num)
print("输入的数字为%d"%num)
# 因为整型数据不能和字符串相加,将会引发TypeError异常,但是程序没有处理该异常对象的except块
# 运行环境终止,python解释器也将退出
num_2 = num + 'a'
break
except ValueError:
input_num = input("输入一个数字:")
continue
4)因为程序的错误类型很多,一般不会让任何错误类型都有相应的except块用于处理错误,但是又不希望在程序引发某种异常却没有该异常对应的except块进而导致程序结束,所以可以在except的最后添加一个可以处理任何异常类型的except块:
input_num = input("输入一个数字:")
while input_num :
try:
num = int(input_num)
print("输入的数字为%d"%num)
num_2 = num + 'a'
break
except ValueError:
input_num = input("输入一个数字:")
continue
except Exception:
print("未知异常")
break
# 输入一个数字:10
# 输入的数字为10
# 未知异常
5)当python解释器接收到异常对象时,会依次判断该异常对象是否是except块后的异常类或者其子类的实例,如果是,Python将调用该except块来处理该异常;如果不是,将判断是否是下一个except块后的异常类或者其子类的实例;
Python的所有异常类都从BaseException继承而来;Python常见异常类的继承关系如下图所示:
如果用户要实现自定义异常,应该继承Exception类;
只要将多个异常类用圆括号括起来,中间以逗号分隔开;
input_num_1 = input("输入一个数字:")
input_num_2 = input("输入一个数字:")
try:
num_1 = int(input_num_1)
num_2 = int(input_num_2)
print("输入数%d和数%d的商为%d"%(num_1, num_2, num_1//num_2))
except(ValueError, ZeroDivisionError):
print("程序引发ValueError异常或者ZeroDivisionError异常")
except Exception:
print("未知异常")
# 输入一个数字:10
# 输入一个数字:0
# 程序引发ValueError异常或者ZeroDivisionError异常
如果程序想要在except块中访问异常对象的相关信息,可以通过为异常对象声明变量来实现;
所有的异常对象都包含以下几个属性和方法:
args | 该属性返回异常的错误编号和描述字符串 |
errno(注:程序显示没有该属性,遗留问题) | 返回异常的错误编号 |
strerror(注:程序显示没有该属性,遗留问题) | 返回异常的描述字符串 |
with_traceback() | 该方法可处理异常的传播轨迹信息 |
input_num_1 = input("输入一个数字:")
input_num_2 = input("输入一个数字:")
try:
num_1 = int(input_num_1)
num_2 = int(input_num_2)
print("输入数%d和数%d的商为%d"%(num_1, num_2, num_1//num_2))
except ValueError as e1:
print("程序引发ValueError异常")
print(e1.args)
# 输入一个数字:a
# 输入一个数字:b
# 程序引发ValueError异常
# ("invalid literal for int() with base 10: 'a'",)
当try块没有出现异常时,程序会执行else块;出现异常else块将不运行;
大多数程序并不需要else块,直接将else块后面的代码放到try块里面就可以;
但是else块绝不是多余的,这是由它自身一个重要的性质决定:else块里的代码引发的异常不会被except块捕获;
所以,如果希望某段代码的异常能被后面的except块捕获,那么就应该将这段代码放在try块,如果希望某段代码的异常能够向外传播(不被except捕获),那么这段代码就放在else块里面:
input_num_1 = input("输入一个数字:")
input_num_2 = input("输入一个数字:")
try:
num_1 = int(input_num_1)
num_2 = int(input_num_2)
print("输入数%d和数%d的商为%d"%(num_1, num_2, num_1//num_2))
except ValueError as e1:
print("程序引发ValueError异常")
print(e1.args)
else:
print("successful")
# 输入一个数字:10
# 输入一个数字:5
# 输入数10和数5的商为2
# successful
程序如果在try块里打开了一些物理资源(例如数据库连接、网络连接或者磁盘文件等),这些物理资源必须被显示回收;
不管try块里的代码是否出现异常,或是在try块或者finally块中执行了return语句,finally块总会被执行(有一种情况不会被执行,稍后会有说明);
try:
print("打开磁盘文件")
input_str = input("输入字符串:\n")
my_file = open("D:/test.txt", "w")
print(input_str, file=my_file)
except Exception:
print("未知异常")
finally:
print("关闭磁盘文件")
my_file.close()
# 打开磁盘文件
# 输入字符串:
# 君不见,黄河之水天上来,奔流到海不复回
# 关闭磁盘文件
当在try块中包含关闭Python解释器的语句:os.exit(1),finally块将不会执行,其实该语句后的所有代码将不运行;
import os
try:
print("打开磁盘文件")
input_str = input("输入字符串:\n")
my_file = open("D:/test.txt", "w")
print(input_str, file=my_file)
os._exit(1)
print("程序还会运行吗")
except Exception:
print("未知异常")
finally:
print("关闭磁盘文件")
my_file.close()
# 打开磁盘文件
# 输入字符串:
# 离离原上草,一岁一枯荣