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何时执行?在
@Martijn Pieters的精彩解释。由于yield在您的案例中是多余的,您可以通过创建自己的上下文管理器(不使用yield和contextlib.contextmanager)。这更简单易读。所以在您的例子中,您可以实现如下内容。在
内部contextlib.contextmanager按照@Martijun Pieters的解释,调用\uuenter\和\uuu exit\uuu魔术函数。希望这有帮助!在
yield
表达式将控制权返回给使用生成器的对象。生成器在此时暂停,这意味着@contextmanager
修饰符知道代码是用设置部分完成的。在换句话说,在上下文管理器
__enter__
阶段中要做的一切都必须在yield
之前发生。在一旦上下文退出(因此
with
语句下的块完成),将为上下文管理器协议的__exit__
部分调用@contextmanager
修饰符,并将执行以下两种操作之一:如果没有异常,它会恢复你的生成器。因此,生成器在
yield
行取消暂停,然后进入清理阶段,该部分如果出现异常,装饰器使用
generator.throw()
在生成器中引发该异常。就好像yield
行导致了这个异常。因为您有一个finally
子句,它将在生成器因异常而退出之前执行。因此,在您的具体例子中,顺序如下:
with time_print("processes"):
这将创建上下文管理器并调用
__enter__
。生成器开始执行,
t = time.time()
运行。yield
表达式暂停生成器,控制返回到装饰器。这将获取所生成的任何内容并将其返回到with
语句,以防存在as target
部分。这里生成None
(只有一个普通的yield
表达式)。[doproc() for _ in range(500)]
运行并完成。上下文管理器
__exit__
方法已运行,未传入异常。装饰者重新启动生成器,它继续执行它停止的地方。
输入
finally:
块并执行print task_name, "took", time.time() - t, "seconds."
。生成器退出,decorator
__exit__
方法退出,一切都完成了。相关问题 更多 >
编程相关推荐