在上下文管理器中无价值的收益是什么 [英] what does yield without value do in context manager
问题描述
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何时执行?
when does doproc get executed when using this decorator?
推荐答案
yield
表达式将控制权返回给使用生成器的对象.此时,生成器暂停,这意味着@contextmanager
装饰器知道代码是由 setup 部分完成的.
yield
expression returns control to the whatever is using the generator. The generator pauses at this point, which means that the @contextmanager
decorator knows that the code is done with the setup part.
换句话说,您要在上下文管理器__enter__
阶段中执行的所有操作都必须在yield
之前进行.
In other words, everything you want to do in the context manager __enter__
phase has to take place before the yield
.
一旦上下文退出(因此with
语句下的块完成),就为上下文管理器协议的__exit__
部分调用@contextmanager
装饰器,它将执行以下两项操作之一:
Once your context exits (so the block under the with
statement is done), the @contextmanager
decorator is called for the __exit__
part of the context manager protocol and will do one of two things:
-
如果没有异常,它将恢复您的生成器.因此,生成器在
yield
行取消暂停,然后进入清理阶段,即
If there was no exception, it'll resume your generator. So your generator unpauses at the
yield
line, and you enter the cleanup phase, the part
如果存在异常,则装饰器使用generator.throw()
在生成器中引发该异常.就像yield
行导致了该异常.因为您有一个finally
子句,它将在生成器由于异常而退出之前执行.
If there was an exception, the decorator uses generator.throw()
to raise that exception in the generator. It'll be as if the yield
line caused that exception. Because you have a finally
clause, it'll be executed before your generator exits because of the exception.
因此,在您的特定示例中,顺序如下:
So, in your specific example the sequence is as follows:
-
with time_print("processes"):
这将创建上下文管理器并在其上调用__enter__
.
This creates the context manager and calls __enter__
on that.
生成器开始执行,t = time.time()
运行.
The generator starts execution, t = time.time()
is run.
yield
表达式会暂停生成器,控制权会回到装饰器.如果有as target
部分,这将采用产生的所有内容,并将其返回给with
语句.产生None
(只有简单的yield
表达式).
The yield
expression pauses the generator, control goes back to the decorator. This takes whatever was yielded and returns that to the with
statement, in case there is an as target
part. Here None
is yielded (there is only a plain yield
expression).
[doproc() for _ in range(500)]
运行并完成.
上下文管理器__exit__
方法正在运行,没有传入任何异常.
The context manager __exit__
method is run, no exception is passed in.
装饰器恢复生成器,从中断处继续.
The decorator resumes the generator, it continues where it left off.
输入finally:
块并执行print task_name, "took", time.time() - t, "seconds."
.
生成器退出,装饰器__exit__
方法退出,全部完成.
The generator exits, the decorator __exit__
method exits, all is done.
这篇关于在上下文管理器中无价值的收益是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!