Python上下文管理器:为何在__enter__方法返回计时逻辑?
解惑Timer上下文管理器的运行逻辑
先看你给出的完整代码:
# timing.py from time import perf_counter class Timer: def __enter__(self): self.start = perf_counter() self.end = 0.0 return lambda: self.end - self.start # Does it not evaluate to 0.0 - self.start??? def __exit__(self, *args): self.end = perf_counter() with Timer() as time: # do something print(time())
核心疑问解答
为什么lambda不会直接返回0.0 - self.start?
lambda是延迟计算的函数对象,在__enter__里它只是被创建并返回,并不会立刻执行self.end - self.start这个表达式。只有当你后续调用time()的时候,才会实际计算这个值——而此时self.end已经被__exit__方法更新为with块执行完毕后的时间,所以得到的是正确的耗时。__enter__并没有被调用两次
你觉得它被调用两次是误解:
- 第一次是进入with块时,系统自动调用
__enter__,记录起始时间并返回lambda函数,这个函数被赋值给time变量 - 后续的
time()是调用那个lambda函数,和__enter__方法没有关系,__enter__全程只执行一次
- 为什么不能把返回逻辑放在__exit__里?
__exit__方法的返回值有特殊作用:它返回True时会抑制with块中抛出的异常,返回False则让异常继续传播。所以它不能用来返回耗时——而且with语句的as绑定的变量是__enter__的返回值,__exit__的返回值根本不会被这个变量接收。
补充说明
这个写法的巧妙之处在于用lambda捕获了Timer实例的self.start和self.end,实现了在with块结束后才计算耗时的效果,同时保持了上下文管理器的标准结构。
内容的提问来源于stack exchange,提问作者Monojit Sarkar
相关产品推荐
相关产品推荐

