4、with语句
说明:with 语句管理资源关闭
with open('data.txt', 'r', True, 'GBK') as f: # 把打开文件放在 with 语句中,可自动关闭文件
print(f.read())
第一行
第二行
第三行
原理:
-
使用 with 语句管理的资源必须是一个实现上下文管理协议(context manage protocol)的类。
-
实现上下文管理协议必须实现两个方法:
-
context_manager._enter_():进入上下文管理器自动调用该方法。
- 该方法会在 with 代码块执行之前执行;
- 若 with 语句有 as子句,那么该方法的返回值会被赋值给 as 子句后的变量;
- 该方法可以返回多个值,因此 as 子句后可指定多个变量(多个变量必须由“()”括起来组成元组)。
-
context_manger._exit_(exc_type, exc_value, exc_traceback):退出上下文管理器自动调用方该方法。
-
该方法会在 with 代码块执行之后执行;
-
若 with 代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为 None;
-
若 with 代码块因为异常而中止,程序也自动调用该方法,使用 sys.exc_info 得到的异常信息将作为调用该方法的参数(可使用 help(sys.exc_info) 查看该函数说明)。
- ex_type:异常类型
- ex_value:异常值,创建异常时传入的所有参数值
- ex_traceback:异常的traceback对象,包含出错的行数、位置等数据。
import traceback import sys try: raise ValueError(10, '抛出异常') # 10 为自定义的异常编号 except Exception as ex: ex_type, ex_value, ex_traceback = sys.exc_info() print(ex_type) print(ex_value) for stack in traceback.extract_tb(ex_traceback): print(stack)
<class 'ValueError'> (10, '抛出异常') <FrameSummary file test.py, line 4 in <module>>
-
-
分析:
- 一个类实现了 __enter__() 和 __exit__(exc_type, exc_value, exc_traceback) 方法,程序就可以使用 with 语句来管理它;
- 通过 __exit__() 方法的参数,即可判断出 with 代码块执行时是否遇到了异常
class FkResource:
def __init__(self, tag):
self.tag = tag
print('---构造方法---')
# 进入with 语句时会执行该方法
def __enter__(self):
print('该资源的tag:', self.tag)
return 'python' # 此处的返回值就是 as 语句中变量的值
def __exit__(self, ex_type, ex_value, ex_traceback):
if ex_traceback: # ex_traceback 若存在,说明因为异常退出
print('出现异常(关闭资源)')
else:
print('正常结束(关闭资源)')
with FkResource('java') as fk:
print('fk为:', fk)
print('before')
print('活动')
print('after')
---构造方法---
该资源的tag: java
fk为: python
before
活动
after
正常结束(关闭资源)
with FkResource('java') as fk:
print('fk为:', fk)
print('before')
raise Exception(10, '自定义异常')
print('after')
---构造方法---
该资源的tag: java
fk为: python
before
出现异常(关闭资源)
--------------------------------------
...(省略)
Exception: (10, '自定义异常')
分析:步骤如下。
- 执行 with 子句后的表达式(FkResource(‘java’))
- 执行__enter__方法,并将改方法的返回值赋值给as子句中的变量
- 在 with 语句块完成或遇到异常时自动执行__exit__方法