Python中的with与上下文管理器
程序员文章站
2022-07-02 21:23:50
...
详细见:https://blog.csdn.net/weixin_35653315/article/details/78158735
with…[as…]
主要用于对象的获取和释放,以及函数默认参数的设定。类似于try…finally…
上下文管理对象(Context Manager, CM)
主要有两个协议方法为__enter__与__exit__, 前者在进入with代码块时执行, 后者在退出时执行.
原始简单cm:
# encoding=utf-8
# !/usr/local/bin/Python3
class reverse_print():
def __enter__(self):
# 这个方法在进入with block时执行.
print('enter with block.')
import sys
self.origin_write = sys.stdout.write
sys.stdout.write = self.new_print# Python2里这个对象不可修改, Python3可以
return 'HELLO, I AM WITH'# 被 as 接收
def new_print(self, s):
self.origin_write(s[::-1])
def __exit__(self, exception_type, exception_code, traceback):
# 跳出with block时执行.
# 处理异常(这儿就忽略吧), 恢复进入with时的修改
import sys
sys.stdout.write = self.origin_write
print('exit with block')
print('before with:', 'hello')
with reverse_print() as cmo:
print('hello')
print(cmo)
print('after with:','hello')
print(cmo)
输出为:
before with: hello
enter with block.
olleh
HTIW MA I ,OLLEH
exit with block
after with: hello
HELLO, I AM WITH
这段代码展示了CMO的两个关键点:
- __enter__在进入with时执行. 它的返回值会被as接收.
- exit 在退出with时执行, 需要将在__enter__对context作出的修改恢复成原样.
使用contextlib.contextmanager 简化CM实现:
import contextlib
@contextlib.contextmanager
def reverse_print():
# 这个方法在进入with block时执行.
import sys
origin_write = sys.stdout.write
print('enter with block.')
def new_print(s):
origin_write(s[::-1])
sys.stdout.write = new_print# Python2里这个对象不可修改, Python3可以
yield 'HELLO, I AM WITH'
# 跳出with block时执行.
# 处理异常(这儿就忽略吧), 恢复进入with时的修改
sys.stdout.write = origin_write
print('exit with block')
用生成器函数重写后的CM, 调用方式与调用效果和用class实现时一模一样.
大概原理:
- 通过修饰器将生成器函数封装到一个CMO class里
- yield之前的代码在__enter__里执行, 之后的代码在__exit__里执行. yield本身的作用相当于__enter__里的return.