异常概述
异常机制已经成为衡量一门编程语言是否成熟的标准之一,使用异常处理机制的Python程序有更好的容错性,更加健康。
异常处理机制
Python的异常处理机制可以让程序具有极好的容错性。
使用try…except捕获异常
语法结构如下:
try:
业务实现代码
except (Error1, Error2,...) as e:
alert 输入不合法
goto retry
如果执行try块里的逻辑代码时出现异常,系统自动生成一个异常对象,该对象被提交给Python解释器,这个过程称为引发异常。
异常类的继承体系
Python的所有异常类的基类是BaseException,但如果用户要实现自定义异常,应该继承Exception。
BaseException的主要子类就是Exception,不管是系统的异常类,还是用户自定义的异常类,都应该从Exception派生。
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print("您输入的两个数相除的结果是:", c )
except IndexError:
print("索引错误:运行程序时输入的参数个数不够")
except ValueError:
print("数值错误:程序只能接收整数参数")
except ArithmeticError:
print("算术错误")
except Exception:
print("未知异常")
实际编程时一定要记住:先捕获小异常,再捕获大异常!
多异常捕获
Python的一个except块可以捕获多种类型的异常,只要将多个异常类用圆括号括起来,中间用逗号隔开即可-----其实就是构建多个异常类的元组
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print("您输入的两个数相除的结果是:", c )
except (IndexError, ValueError, ArithmeticError):
print("程序发生了数组越界、数字格式异常、算术异常之一")
except:
print("未知异常")
else块
在Python的异常处理流程中还可添加一个else块,当try块没有出现异常时,程序会执行else块。
如果希望某段代码的异常能被后面 except 块捕获,那么就应该将这段代码放在 try块的代码之后;如果希望某段代码的异常能向外传播,那么久应该将这段代码放在else块中。
使用finally回收资源
为了保证一定能回收在try块中打开的资源,异常处理机制提供了finally块,不管try块中的代码是否出现异常,也不管哪一个except块被执行,甚至在try块或except块中执行了return语句,finally块总会被执行。Python完整的异常处理语法结构如下:
try:
业务实现代码
except SubException as e:
异常处理块1
except SubException2 as e:
异常处理块2
...
else:
正常处理块
finally:
资源回收块
异常处理嵌套
在try块、except块、finally块中包含一个完整的异常处理流程的情形称为异常处理嵌套。
使用raise引发异常
引发异常
如果需要在程序中自行引发异常,可以使用raise语句。raise语句有三种常用的用法:
- raise:单独一个raise。该语句引发当前上下文中捕获的异常或默认引发runtimeError异常
- raise异常类:raise后带一个异常类。该语句引发指定异常类的默认实例
- raise异常对象:引发指定的异常对象
自定义异常类
用户自定义异常都应该继承Exception基类或Exception子类,在自定义异常类时只需要指定自定义异常类的父类即可
except和raise同时使用
在异常出现的当前方法中,程序只对异常进行部分处理,还有些处理需要在该方法的调用中才能完成,所以应该再次引发异常,让该方法的调用者也能捕获到异常。为了实现这种通过多个方法协作处理同一个异常的情形,可以在except块中结合raise语句来完成。
这种except和raise结合使用的情况再实际应用中非常常用。实际应该对异常处理通常分为两个部分:1、应用后台需要通过日志来记录异常发生的详细情况;2、应用还需要根据异常向应用使用者传达某种提示。
raise不需要参数
使用raise语句时可以不带参数,此时raise语句处于except块中,它将会自动引发当前上下文激活的异常;否则,通常默认引发runtimeError异常
Python的异常传播轨迹
Python专门提供了traceback模块来处理异常传播轨迹,导入traceback模块之后,提供了如下两个常用方法。
- traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中
- format_exc():将异常传播轨迹信息转换成字符串
异常处理规则
成功的异常处理应该实现如下4个目标:
- 使程序代码混乱最小化
- 捕获并且保留诊断信息
- 通知合适的人员
- 采用合适的方式结束异常活动
不要过度使用异常
过度使用异常主要表现在两个方面:
- 把异常和普通错误混淆在一起,不再编写任何错误处理代码,而是以简单地引发异常来代替所有的错误处理
- 使用异常处理来代替流程控制
不要使用过于庞大的try块
try块里的代码过于庞大,业务过于复杂,就会造成try块中出现异常的可能性大大增加,从而导致分析异常原因的难度也大大增加。
不要忽略捕获到的异常
不要忽略异常!既然已捕获到异常,那么except块理应做处理并修复异常。
- 处理异常
- 重新引发新异常
- 在合适的层处理异常
练习题
1、提示用户输入一个N,表示用户接下来要输入N个字符串,程序尝试将用户输入的每一个字符串用空格分割成两个整数,并结算这两个整数
整除的结果。
要求:使用异常处理机制来处理用户输入的各种错误,并提示用户重新输入。将最后计算的结果存入列表并打印
num = input("请输入一个N:")
num_list = []
try:
i = 0
while(True):
num_str = input("请输入以空格分隔的两个整数:")
try:
x,y = num_str.split(' ')
print("%d整除%d的结果是:%d" %(int(x),int(y),int(x)//int(y)))
num_list.append(int(x)//int(y))
i +=1
if i>= int(num):
break
except ValueError:
print("必须输入两个以空格隔开的整数,请重新输入!")
continue
except ValueError:
print("请输入正整数!")
finally:
print("最终的结果列表是:%s" % num_list)
2、提示用户输入一个整数,如果用户输入的整数是奇数,则输出“有趣”;如果用户输入的整数是偶数,且在2~5 之间,则打印“没意思”;
如果用户输入的整数是偶数,且在6~20 之间,则输出“有趣”;如果输入的整数是其他偶数,则打印“没意思”。
要求:使用异常处理机制来处理用户输入的各种错误情况
n = input("请输入一个整数:")
try:
num = int(n)
while (num >= 0):
if num % 2 != 0:
print("有趣")
elif num % 2 == 0 and num >= 2 and num <= 5:
print("没意思")
elif num % 2 == 0 and num >= 2 and num <= 5:
print("有趣1")
else:
print("没意思1")
else:
print("不能输入负数")
except ValueError:
print("请输入整数!")
3、提供一个字符串元组,程序要求元组中每一个元素的长度都在5~20 之间:否则, 程序引发异常。
str = ("Python语言学习","疯狂Python学习","学习","23")
for i in str:
if len(i)>=5 and len(i)<=20:
print(i)
else:
print("元素:'%s' 长度必须在5~20之间!" % i)
4、提示用户输入x1, y1, x2, y2, x3, y3 六个数值,分别代表三个点的坐标,程序判断这三个点是否在同一条直线上。要求: 使用异常处理机制处理用户输入的各种错误情况,如果三个点不在同一条直线上,则程序出现异常
try:
x1, y1, x2, y2, x3, y3 = input('请依次输入6个坐标点以空格隔开').split(' ')
x1 = float(x1)
y1 = float(y1)
x2 = float(x2)
y2 = float(y2)
x3 = float(x3)
y3 = float(y3)
if x1 == 0 and x2 == 0 and x3 == 0:
print('三个点在一条直线上')
elif 0 in (x1, x2, x3):
raise Exception('三个点不在同一直线上')
elif y1 / x1 == y2 / x2 and y1 / x1 == y3 / x3:
print('三个点在同一直线上')
else:
raise Exception('三个点不在同一直线上')
except ValueError:
print('输入的坐标必须为数字!')