六、异常处理
Python的异常机制主要依赖try、except、else、finally、raise五个关键字,其中在try关键字后缩进的代码块简称try块,里面放置的是可能引发异常的代码;在except后对应的是异常类型和一个代码块,用于表明该except块处理的这种类型的代码块;在多个except后可以放一个else块,表明程序不出现异常时需要在执行else部分;最后添加finally块,总被执行;raise用于引发一个实际的异常,raise可以单独作为语句使用,引发一个具体的异常对象。
1、异常概述
错误处理机制两大缺点:
- 无法穷举所有的异常情况;
- 错误处理代码和业务实现代码混杂;
2、异常处理机制
2.1、使用try…except捕获
try:
except (Error1, Error2, ... ): as e:
alert 输入不合法
goto retry
如果在执行try块里的业务逻辑代码时出现异常,系统自动生成一个异常对象,该异常对象被提交给Python解释器,过程被称之为引发异常。 当Python解释器收到异常对象时,会寻找能处理该异常对象的except块,如果找到合适的except块,则把该异常对象交给该except块处理,过程被称之为捕获异常。 如果无法捕获异常,则运行时环境终止,Python解释器退出。
InputInt = input("请输入整型数据:\n")
try:
if int(InputInt) >= 18:
print('成年!')
else:
print("未成年!")
except:
print('输入数据类型有误,请重新输入')
2.2、异常类的继承体系
当Python解释器接收到异常对象后,会依次判断该异常对象是否是except块后的异常类或其子类的实例,如果是,Python解释器将调用该except块来处理该异常;否则,再次拿该异常对象和下一个except块里的异常类进行比较。 Python捕获异常的流程图:
try:
statement1
statement1
...
except Exception1:instance(ex, Exception1)
exception handler statement1
...
except Exception2:instance(ex, Exception2)
exception handler statement1
...
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print('两数相除的结果是:{0}'.format(c))
except IndexError:
print("索引错误,运行程序时输入的参数个数不够")
except ValueError:
print("数值错误,程序运行只能接受整数")
except ArithmeticError:
print("算数错误")
except Exception:
print("未知错误")
IndexError:输入的参数不够,将会发生索引错误; ValueError:输入的参数不是数字,而是字母等,将会发生数值错误; ArithmeticError:除0异常,将会发生算数错误; Exception:其他异常;
2.3、多异常捕获
Python的一个except块可以捕获多种类型的异常。 在使用一个except块捕获多种类型的异常时,只要将多个异常类用圆括号括起来,中间用逗号隔开即可(构建多个异常类的元组)。
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print('两数相除的结果是:{0}'.format(c))
except (IndexError, ValueError, ArithmeticError):
print("索引错误/数值错误/算法错误")
except Exception:
print("未知错误")
2.4、访问异常信息
在except块中访问异常对象的相关信息,通过为异常对象声明变量来实现。
- args:该属性返回异常的错误编号和描述字符串;
- errno:返回异常的错误编号;
- strerror:返回异常的描述字符串;
- with_traceback():通过该方法可处理异常的传播轨迹信息;
def foo():
try:
fis = open("a.txt")
except Exception as e:
print(e.args)
foo()
2.5、else块
当try没有出现异常时,程序会执行else块
s = input("请输入除数:\n")
try:
result = 20 / int(s)
print(result)
except ValueError:
print("输入数值错误")
else:
print('无异常')
2.6、使用finally回收资源
finally总会被执行,切必须放在所有except块之后。
s = '12'
try:
result = 20 / int(s)
print(result)
except ValueError:
print("输入数值错误")
else:
print('无异常')
finally:
print('结束')
2.7、异常处理嵌套
在finally块中包含了一个完整的异常处理流程
import os
def test():
fis = None
try:
fis = open("a.txt")
except OSError as e:
print(e.strerror)
return
finally:
if fis is not None:
try:
fis.close()
except OSError as ioe:
print(ioe.strerror)
print("资源回收")
test()
3、使用raise引发异常
当程序出现错误时,系统会自动引发异常。之外Python可以使用raise自行引发异常。
3.1、引发异常
系统需要引发异常,可能需要根据应用业务需求来决定,如果程序中的数据、执行与既定的业务需求不符,则为一种异常。由于与业务需求不符的异常,需要自行引发异常。 自行引发异常:raise语句
- raise:单独一个raise。该语句引发当前上下文中捕获异常(比如在except块中)或者默认引发RunnerTime异常。
- raise异常类:raise后带一个异常类。该语句引发指定类的默认实例;
- raise异常对象:引发指定的异常对象;
上面三种方法最终都是要引发一个异常实例,且每次只能引发一个异常实例。
3.2、自定义异常类
class AuctionExpection(Exception):
pass
3.3、except和raise同时使用
在异常出现的当前方法中,程序只对异常部分进行处理,还有些处理需要在该方法的调用者中才能完成。应再次引发异常,让该方法的调用者也能够捕获异常。
class AuctionExpection(Exception):
pass
class AutionTest:
def __init__(self, init_price):
self.init_price = init_price
def bid(self, bid_price):
d = 0.0
try:
d = float(bid_price)
except Exception as e:
print(e)
raise AuctionExpection("AAA")
if self.init_price > d:
raise AuctionExpection("BBB")
initPrice = d
def main():
at = AutionTest(20.4)
try:
at.bid("df")
except AuctionExpection as ae:
print(ae)
main()
3.4、raise不需要参数
在使用raise语句时不带参数,此事raise处于except块中,将自动引发当前上下文激活的异常。
4、Python的异常传播轨迹
异常对象提供了一个with_traceback用于处理异常的传播轨迹,查看异常的传播轨迹可跟踪异常触发的源头,也可看到异常一路触发的轨迹。
class SelfException(Exception):
pass
def main():
firstMethod()
def firstMethod():
secondMethod()
def secondMethod():
thirdMethod()
def thirdMethod():
raise SelfException("自定义异常信息")
main()
Traceback (most recent call last):
File "G:\AAA\111.py", line 123, in <module>
main()
File "G:\AAA\111.py", line 116, in main
firstMethod()
File "G:\AAA\111.py", line 118, in firstMethod
secondMethod()
File "G:\AAA\111.py", line 120, in secondMethod
thirdMethod()
File "G:\AAA\111.py", line 122, in thirdMethod
raise SelfException("自定义异常信息")
__main__.SelfException: 自定义异常信息
异常从发生异常的函数或方法逐渐向外传播,首先传给该函数或方法的调用者,该函数或方法的调用者再传递给其他调用者…直至传递到Python解释器,此时Python解释器会中止该程序,并打印异常的传播轨迹信息。 Python提供了traceback模块来处理异常传播轨迹,使用traceback可以方便地处理Python的异常传播轨迹、导入traceback模块后,traceback提供了如下两个方法:
- traceback.print_exc():将异常传播轨迹输出到控制台或指定文件中;
- format_exc():将异常传播信息转换成字符串;
- etype:指定异常类型;
- value:指定异常值;
- tb:指定异常的traceback信息;
- limit:用于限制显示异常传播的层数;
- file:指定将异常传播轨迹信息输出到指定文件中;
import traceback
class SelfException(Exception):
pass
def main():
firstMethod()
def firstMethod():
secondMethod()
def secondMethod():
thirdMethod()
def thirdMethod():
raise SelfException("自定义异常信息")
try:
main()
except:
traceback.print_exc()
traceback.print_exc(file=open('log.txt', 'a', encoding='utf-8'))
5、异常处理规则
议程处理目标点:
- 使程序代码混乱最小化;
- 捕获并保留诊断信息;
- 通知合适的人员;
- 采用合适的方式结束异常活动;
5.1、不要过度使用异常
|