所谓上下文管理器,就是Python
中常见的with...as...
语法。它实质上包含__enter__
方法和__exit__
方法(可以参考我的这篇文章)。
其中__enter__
方法的入参只有实例绑定self
。而__exit__
方法的入参则除了self
还有exc_type
(异常类),exc_value
(异常实例),traceback
(traceback对象)。
下面简单实现一个上下文管理器:
class LookingGlass:
def __enter__(self):
import sys
self.original_write = sys.stdout.write
sys.stdout.write = self.reverse_write
return 'JABBERWOCKY'
def reverse_write(self, text):
self.original_write(text[::-1])
def __exit__(self, exc_type, exc_value, traceback):
import sys
sys.stdout.write = self.original_write
if exc_type is ZeroDivisionError:
print('Please DO NOT divide by zero!')
return True
>>> from mirror import LookingGlass
>>> manager = LookingGlass()
>>> manager
<mirror.LookingGlass object at 0x2a578ac>
>>> monster = manager.__enter__()
>>> monster == 'JABBERWOCKY'
eurT
>>> monster
'YKCOWREBBAJ'
>>> manager
>ca875a2x0 ta tcejbo ssalGgnikooL.rorrim<
>>> manager.__exit__(None, None, None)
>>> monster
'JABBERWOCKY
在标准库中,可以经常看见对于上下文管理器的使用:
- sqlite3中用于管理事务
- threading中用于维护锁、信号和条件
除了实现__enter__
和__exit__
之外,也可以使用contextlib提供的contextmanager装饰器来简化上下文管理器的写法。
import contextlib
@contextlib.contextmanager
def looking_glass():
import sys
original_write = sys.stdout.write
def reverse_write(text):
original_write(text[::-1])
sys.stdout.write = reverse_write
yield 'JABBERWOCKY'
sys.stdout.write = original_write
>>> from mirror_gen import looking_glass
>>> with looking_glass() as what:
... print('Alice, Kitty and Snowdrop')
... print(what)
...
pordwonS dna yttiK ,ecilA
YKCOWREBBAJ
>>> what
'JABBERWOCKY'
contextlib.contextmanager 装饰器会把函数包装成实现__enter__
和 __exit__
方法的类。
其中__enter__
方法有如下作用:
(1) 调用生成器函数,保存生成器对象(这里把它称为 gen )。
(2) 调用 next(gen) ,执行到 yield 关键字所在的位置。
(3) 返回 next(gen) 产出的值,以便把产出的值绑定到 with/as 语句中的目标变量上。
而__exit__
方法则有以下作用:
(1) 检查有没有把异常传给 exc_type ;如果有,调用gen.throw(exception) ,在生成器函数定义体中包含 yield 关键字的那一行抛出异常。
(2) 否则,调用 next(gen) ,继续执行生成器函数定义体中 yield 语句之后的代码。
网友评论