题目
实现一个自定义上下文管理器,用于测量代码块的执行时间
信息
- 类型:问答
- 难度:⭐⭐
考点
上下文管理器, 时间测量, with语句, 异常处理
快速回答
实现要点:
- 使用
__enter__记录开始时间 - 使用
__exit__计算时间差并输出 - 处理异常时保持计时功能
- 支持自定义时间单位和输出格式
1. 核心原理
Python上下文管理器通过__enter__和__exit__方法实现:
__enter__:进入上下文时执行,返回资源对象__exit__:退出上下文时执行,处理清理工作
time模块的perf_counter()(高精度计时器)实现时间测量。2. 代码实现
import time
class Timer:
def __init__(self, unit='s', fmt='{:.4f}'):
self.unit = unit # 时间单位('s','ms')
self.fmt = fmt # 输出格式
def __enter__(self):
self.start = time.perf_counter()
return self # 返回自身以便访问结果
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.perf_counter()
self.duration = self.end - self.start
# 单位转换
if self.unit == 'ms':
self.duration *= 1000
# 异常处理:返回False会传播异常,True则抑制
print(f"Execution time: {self.fmt.format(self.duration)}{self.unit}")
return False
# 使用示例
with Timer(unit='ms') as t:
time.sleep(0.5)
# 此处可引发异常测试
print(f"外部访问: {t.duration:.2f}ms")3. 最佳实践
- 高精度计时:使用
perf_counter()而非time(),避免系统时间调整影响 - 异常安全:在
__exit__中处理异常后应返回False(不抑制异常) - 资源访问:通过返回
self允许外部访问计时结果 - 灵活性:支持自定义单位和输出格式
4. 常见错误
- 错误计时:在
__init__中初始化时间(应在__enter__) - 忽略异常:
__exit__中直接返回True会吞掉异常 - 精度不足:使用
time.time()可能受系统时钟影响
5. 扩展知识
- 上下文管理器协议:
__exit__接收三个异常参数(类型/值/回溯) - 替代实现:使用
@contextmanager装饰器+生成器:from contextlib import contextmanager @contextmanager def timer(unit='s'): start = time.perf_counter() try: yield # 在此处执行代码块 finally: end = time.perf_counter() duration = (end - start) * (1000 if unit=='ms' else 1) print(f"Time: {duration:.4f}{unit}") - 性能分析:复杂场景建议使用
cProfile模块