异常堆栈跟踪
有时需要知道更多异常信息时,可以打印堆栈跟踪信息。堆栈跟踪信息可以通过python内置模块 traceback 提供的 print_exc() 函数实现,print_exc() 函数的语法格式如下:
traceback.print_exc(limit = None, file = None,chain = True)
其中,参数 limit 限制堆栈跟踪的个数,默认为 None 表示不限制;参数 file 为是否输出堆栈跟踪信息到文件,默认None 是不输出到文件; 参数 chain 为True,则将 _cause_ 和 _context_ 等属性串联起来,就像解释器本身打印未处理信息一样。
示例代码如下
import datetime as dt
import traceback as tb # 导入traceback模块并命名为 tbdef 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 dateexcept(ValueError,OSError) as e:print("调用方法method1处理...")tb.print_exc() # 打印异常堆栈信息date = read_date_from_file('openfile.txt')
print("日期 = {0}".format(date))
代码运行结果
Traceback (most recent call last):File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 9, in read_date_from_filedate = dt.datetime.strptime(in_date,'%Y-%m-%d')^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\86198\AppData\Local\Programs\Python\Python312\Lib\_strptime.py", line 554, in _strptime_datetimett, fraction, gmtoff_fraction = _strptime(data_string, format)^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "C:\Users\86198\AppData\Local\Programs\Python\Python312\Lib\_strptime.py", line 333, in _strptimeraise ValueError("time data %r does not match format %r" %
ValueError: time data '' does not match format '%Y-%m-%d'
调用方法method1处理...
日期 = None
堆栈信息从上到下为程序执行过程中函数(或方法)的调用顺序,其中的每条信息明确指出了哪一个文件、哪一行、调用哪个函数或方法。
释放资源
有时 try--except 语句会占用一些资源,如打开文件、网络连接、打开数据库连接等,这些资源不能通过 python 的垃圾收集器回收,需要程序员释放,为了确保这些资源释放,可以使用 finally 代码块或 with as 自动资源管理。
finally代码块
try-except 代码块后面可以有finally代码块,次数无论 try 中的代码块正常结束还是 except 异常结束都会执行 finally 代码块。
在上面的程序中,只需要在 try-catch 代码块后加入下面的代码
finally:file.close() # 关闭文件释放资源
else代码块
try 语句月可以带有 else 代码块,它是在程序正常结束时执行的代码块,经过上面的更改(即加入finally代码块)会可以发现,程序仍不够完善,出现的问题是:若文件未成功打开,程序也会进入finally代码块执行 file.close()关闭文件,这会导致一些问题。可以加入 else 语句来解决
示例代码如下
import datetime as dt
import traceback as tb # 导入traceback模块并命名为 tbdef read_date_from_file(filename):'''如果正常打开文件,程序执行else代码块else中嵌套了try语句,在这个try文件中读取文件内容和解析日期最后在嵌套try对应的finally代码块中执行file.close()关闭文件'''try:file = open(filename)except(ValueError,OSError) as e:print("文件打开失败")tb.print_exc() # 打印异常堆栈信息else:print("文件打开成功")try:in_date = file.read()in_date = in_date.strip()date = dt.datetime.strptime(in_date, '%Y-%m-%d')return dateexcept(ValueError, OSError) as e:print("文件打开失败")tb.print_exc() # 打印异常堆栈信息finally:file.close() # 关闭文件释放资源date = read_date_from_file('openfile.txt')
print("日期 = {0}".format(date))
with as代码块自动管理
上面更改后的代码虽然健壮,但程序流程比较复杂,这样的程序难以维护。python提供了 with as 代码块帮助自动释放资源,with as 提供的代码块中,在 as 后面声明一个资源变量,当with as 代码块结束之后自动释放资源。
示例代码如下
import datetime as dt
import traceback as tb # 导入traceback模块并命名为 tbdef read_date_from_file(filename):try:with open(filename) as file:in_date = file.read()in_date = in_date.strip()date = dt.datetime.strptime(in_date, '%Y-%m-%d')return dateexcept(ValueError,OSError) as e:print("文件打开失败")tb.print_exc() # 打印异常堆栈信息date = read_date_from_file('openfile.txt')
print("日期 = {0}".format(date))
在 with as 代码块中包含了资源对象相关代码,完成后自动释放资源。采用了自动资源管理后不再需要 finally 代码块,不需要自己释放资源。
注意:所有可以自动管理的资源,需要实现上下文管理协议。
自定义异常类
实现自定义异常类需要继承 Exception 类及其子类
示例代码如下
class MyException(Exception):def __init__(self,message): # 定义构造方法类,其中参数message是异常描述信息super.__init__(message) # 调用父类构造方法并把参数message传入给父类构造方法
显式抛出异常
前面提到的异常都是系统生成的,当异常抛出时,系统会创建一个异常对象,并将其抛出。我们自己也可以通过 raise 语句显式抛出异常,这样做的目的有很多,如:不想某些异常传给上层调用者,可以捕获之后程序显式抛出另外一种异常给调用者。raise 显式抛出的异常与系统生成并抛出的异常在处理方式上没有区别,都是要么捕获自己处理,要么抛出给上层调用者。
显式抛出异常语法格式如下:
raise BaseException 或其子类的实例
示例代码如下
import datetime as dt
class MyException(Exception):def __init__(self,message):super.__init__(message)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 dateexcept ValueError as e:raise MyException('不是有效日期')except FileNotFoundError as e:raise MyException('文件找不到')except OSError as e:raise MyException('文件无法打开或无法读取')date = read_date_from_file('file.txt')
print('日期 = {0}'.format(date))
代码运行结果如下
Traceback (most recent call last):File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 8, in read_date_from_filefile = open(filename)^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'file.txt'During handling of the above exception, another exception occurred:Traceback (most recent call last):File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 20, in <module>date = read_date_from_file('file.txt')^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 16, in read_date_from_fileraise MyException('文件找不到')^^^^^^^^^^^^^^^^^^^^^^^^^File "D:\creation\PythonStudy\Pythonproject\mypro01\mypy01.py", line 4, in __init__super.__init__(message)
TypeError: descriptor '__init__' requires a 'super' object but received a 'str'Process finished with exit code 1
参考书籍:《python从小白到大牛》(第2版)关东升 编著