436 字
2 分钟
上下文管理器
在 python 开发的过程中,我们通常会用到 with,而 with 的背后就是上下文管理器
With 语法
f = open('1.txt')for line in f: ...f.close()# 上面的代码会导致文件读取期间出现异常的话文件句柄无法释放# 对于这种情况,我们可以使用with来解决with open('1.txt') as f: for line in f: ...
上下文管理器
那么 with 后面的代码是可以随意地吗?
with context_expression [as target(s)]: with-body
答案是否定的,with 后的代码需要实现上下文管理器协议
在 python 中,只要实现了刷新方法就实现了上下文管理器协议
__enter__
: 在进入 with 前调用,会赋值给 with 的 target__exit__
: 退出 with 调用,一般作为异常处理
```pythonclass TestContext:
def __enter__(self): print('__enter__') return 1
def __exit__(self, exc_type, exc_value, exc_tb): print('exc_type: %s' % exc_type) print('exc_value: %s' % exc_value) print('exc_tb: %s' % exc_tb)
with TestContext() as t: print('t: %s' % t)
Contextlib 模块
对于需要上下文管理的场景,除了自己实现 enter 和 exit,另一种方法就是使用 contextlib 模块
使用了 contextlib,就可以把上下文当做一个装饰器来使用
from contextlib import contextmanager
@contextmanagerdef test(): print('before') yield 'hello' print('after')
with test() as t: print(t)
- 执行
test()
方法,先打印出before
- 执行
yield 'hello'
,test
方法返回,hello
返回值会赋值给with
语句块的t
变量 - 执行
with
语句块内的逻辑,打印出t
的值hello
- 又回到
test
方法中,执行yield
后面的逻辑,打印出after
不过有一点需要我们注意:在使用contextmanager
装饰器时,如果被装饰的方法内发生了异常,那么我们需要在自己的方法中进行异常处理,否则将不会执行yield
之后的逻辑。