You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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())

核心疑问解答

  1. 为什么lambda不会直接返回0.0 - self.start?
    lambda是延迟计算的函数对象,在__enter__里它只是被创建并返回,并不会立刻执行self.end - self.start这个表达式。只有当你后续调用time()的时候,才会实际计算这个值——而此时self.end已经被__exit__方法更新为with块执行完毕后的时间,所以得到的是正确的耗时。

  2. __enter__并没有被调用两次
    你觉得它被调用两次是误解:

  • 第一次是进入with块时,系统自动调用__enter__,记录起始时间并返回lambda函数,这个函数被赋值给time变量
  • 后续的time()是调用那个lambda函数,和__enter__方法没有关系,__enter__全程只执行一次
  1. 为什么不能把返回逻辑放在__exit__里?
    __exit__方法的返回值有特殊作用:它返回True时会抑制with块中抛出的异常,返回False则让异常继续传播。所以它不能用来返回耗时——而且with语句的as绑定的变量是__enter__的返回值,__exit__的返回值根本不会被这个变量接收。

补充说明

这个写法的巧妙之处在于用lambda捕获了Timer实例的self.start和self.end,实现了在with块结束后才计算耗时的效果,同时保持了上下文管理器的标准结构。

内容的提问来源于stack exchange,提问作者Monojit Sarkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:27:20