来源:《Python从小白到大牛》关东升
1、捕获异常
在面对异常时,当前函数有能力解决,则捕获异常进行处理;没有能力解决,则抛给上层调用者(函数)处理。如果上层调用者还无力解决,则继续抛给它的上层调用者。异常就是这样向上传递直到有函数处理它。如果所有函数都没有处理该异常,那么Python解释器会终止程序运行。这就是异常的传播过程。
1.1 try-except语句
捕获异常是通过try-except语句实现的,最基本的try-except语句语法如下:
try:
<可能会抛出异常的语句>
except [异常类型]:
<处理异常>
1)try代码块
try代码块中包含执行过程中可能会抛出异常的语句。
2)except代码块
每个try代码块可以伴随一个或多个except代码块,用于处理try代码块中所有可能抛出的多种异常。except语句中如果省略“异常类型”,即不指定具体异常,则会捕获所有类型的异常;如果指定具体类型异常,则会捕获该类型异常,以及它的子类型异常。
1.2多except代码块
如果try代码块中有很多语句抛出异常,而且抛出的异常种类有很多,那么可以在try后面跟有多个except代码块。多except代码块语法如下:
try:
<可能会抛出异常的语句>
except [异常类型I]:
<处理异常>
except [异常类型II]:
<处理异常>
...
except [异常类型n]:
<处理异常>
在多个except代码情况下,当一个except代码块捕获到一个异常时,其他的except代码块就不再进行匹配。
注意:当捕获的多个异常类之间存在父子关系时,捕获异常顺序与except代码块的顺序有关。从上到下先捕获子类,后捕获父类。否则子类捕获不到。
1.3try-except语句嵌套
Python提供了try-except语句是可以任意嵌套的。程序执行时如果内层抛出异常,首先由内层except进行捕获,如果捕获不到,则由外层except捕获。
注意:try-except不仅可以嵌套在try代码块中,还可以嵌套在except代码块或finally代码块,finally代码块后面会详细介绍。try-except嵌套会使程序流程变得复杂,如果能用多except捕获的异常,尽量不要使用try-except嵌套。要梳理好程序的流程再考虑try-except嵌套的必要性。
1.4多重异常捕获
多个except代码块客观上提高了程序的健壮性,但是也大大增加了程序代码量。有些异常种类不同,当捕获之后的处理是相同的。
try:
<可能会抛出异常的语句>
except ValueError as e:
<调用方法method处理>
except OSError as e:
<调用方法method处理>
except FileNotFoundError as e:
<调用方法method处理>
三个不同类型的异常,要求捕获之后的处理都是调用method方法。是否可以把这些异常合并处理呢?Python中可以把这些异常放到一个元组中,这就是多重异常捕获,可以帮助解决此类问题。
# coding=utf-8
import datetime as dt
def read_date_from_file(filename):
try:
file=open(filename)
in_date=file.read()
in_date=in_date.strip()
date=dt.datetime.strptime(in_date,'%Y-%m-%d')
return date
except (ValueError,OSError) as e:
print('调用方法method1处理...')
print(e)
代码中(ValueError,OSError)就是多重异常捕获。
2、异常堆栈跟踪
有时从程序员的角度需要知道更加详细的异常信息时,可以打印堆栈跟踪信息。堆栈跟踪信息可以通过Python内置模块traceback提供的print_exc()函数实现,print_exc()函数的语法格式如下:
traceback.print_exc(limit=None,file=None,chain=True)
其中,参数 limit 限值堆栈跟踪的个数,默认 None 是不限制;参数 file 判断是否输出堆栈跟踪信息到文件,默认 None 是不输出到文件;参数 chain 为 True ,则将__cause__和__context__等属性串联起来,就像解释器本身打印未处理异常一样打印。
提示:在捕获到异常之后,通过print_exc()函数打印异常堆栈跟踪信息,往往只是用于调试,给程序员提示信息。堆栈跟踪信息对最终用户是没有意义的。捕获到异常之后应该给用户弹出一个对话框,提示用户输入日期无效,请用户重新输入,用户重新输入后再重新调用上述函数。这才是捕获异常之后的正确处理方法。
3、释放资源
有时try-except语句会占用一些资源,如打开文件、网络连接、打开数据库连接和使用数据结果集等,这些资源不能通过Python的垃圾收集器回收,需要程序员释放。为了确保这些资源能够被释放,可以使用finally代码块或with as 自动资源管理。
3.1 finally代码块
try-except语句后面还可以跟有一个finally代码块,try-except-finally语句语法如下:
try:
<可能会抛出异常的语句>
except [异常类型I]:
<处理异常>
except [异常类型II]:
<处理异常>
...
except [异常类型n]:
<处理异常>
finally:
<释放资源>
无论是try正常结束还是except异常结束都会执行finally代码块。
如果抛出了异常也会执行finally代码块,可以使用else解决该问题。
3.2 else代码块
与while和for循环类似,try语句也可以带有else代码块,它是在程序正常结束时执行的代码块。
try:
<可能会抛出异常的语句>
except [异常类型I]:
<处理异常>
except [异常类型II]:
<处理异常>
...
except [异常类型n]:
<处理异常>
else:
<执行语句>
finally:
<释放资源>
3.3 with as 代码块自动资源管理
上述程序虽然"健壮",但程序流程比较复杂,这样的程序代码难以维护。为此Python提供了一个with as代码块帮助自动释放资源,它可以替代finally代码块,优化代码结构,提高程序可读性。with as提供了一个代码块,在as 后面声明一个资源变量,当 with as代码块结束时自动释放资源。
4、自定义异常类
有些公司为了提高代码的可重用性,自己开发了一些Python类库,其中有自己编写的一些异常类。实现自定义异常类需要继承Exception类或其子类。
# coding utf-8
class MyException(Exception):
def __init__(self,message):
super().__init__(message)
上述代码实现了自定义异常,代码定义了构造方法类,其中的参数message是异常描述信息。super().init(message)是调用父类构造方法,并把参数message传入给父类构造方法。自定义异常就是这样简单,只需要提供一个字符串参数的构造方法就可以了。
5、显示抛出异常
除了系统创建的异常,也可以通过raise语句显示抛出异常,语法格式如下:
raise BaseException或其子类的实例
显示抛出异常的目的有很多,例如不想某些异常传给上层调用者,可以捕获之后重新显示抛出另外一种异常给调用者。
注意:raise显示抛出的异常与系统生成并抛出的异常在处理方式上没有区别,就是两种方法,要么捕获自己处理,要么抛给上层调用者。
383

被折叠的 条评论
为什么被折叠?



