import contextlib
import time
@contextlib.contextmanager
def time_print(task_name):
t = time.time()
try:
yield
finally:
print task_name, "took", time.time() - t, "seconds."
def doproc():
x=1+1
with time_print("processes"):
[doproc() for _ in range(500)]
# processes took 15.236166954 seconds.
使用这个装饰器时doproc什么时候执行?
最佳答案
yield
表达式将控制权返回给使用生成器的任何对象。生成器在此时暂停,这意味着 @contextmanager
装饰器知道代码已完成 setup 部分。
换句话说,你想在上下文管理器 __enter__
阶段做的所有事情都必须在 yield
之前发生。
一旦您的上下文退出(因此 with
语句下的 block 完成),@contextmanager
装饰器将被调用用于 __exit__
部分上下文管理器协议(protocol),并将做两件事之一:
如果没有异常,它将恢复您的生成器。所以你的生成器在
yield
行取消暂停,然后你进入清理阶段,部分如果出现异常,装饰器会使用
generator.throw()
在生成器中引发该异常。就好像yield
行导致了那个异常。因为您有一个finally
子句,它会在您的生成器因异常而退出之前执行。
因此,在您的特定示例中,顺序如下:
使用 time_print("processes"):
这将创建上下文管理器并对其调用
__enter__
。生成器开始执行,
t = time.time()
运行。yield
表达式暂停生成器,控制权返回装饰器。如果有as target
部分,这将获取生成的任何内容并将其返回给with
语句。这里生成了None
(只有一个普通的yield
表达式)。[doproc() for _ in range(500)]
运行并完成。运行上下文管理器
__exit__
方法,没有传入异常。装饰器恢复生成器,它从中断处继续。
进入
finally:
block 并执行print task_name, "took", time.time() - t, "seconds."
。生成器退出,装饰器
__exit__
方法退出,全部完成。
关于python - yield without value 在上下文管理器中做什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35489844/