timeit.timeit() 的 setup 参数用于前置初始化,避免将 import 或变量赋值开销计入测试;应将依赖全放 setup,stmt 仅留待测语句;作用域隔离需注意,命令行用 -s 预定义;优先用 repeat 取最小值而非平均值;timeit 仅适合纯 cpu 计算场景。

timeit.timeit() 的 setup 参数为什么总被忽略
很多人直接把测试代码塞进 stmt,却忘了初始化变量或导入模块——结果测的不是函数执行时间,而是 import 或赋值开销。比如测 json.loads() 却没提前定义好字符串,每次调用都重新生成,setup 就是干这个的。
实操建议:
Python v2.4版chm格式的中文手册,内容丰富全面,不但是一本手册,你完全可以把她作为一本Python的入门教程,教你如何使用Python解释器、流程控制、数据结构、模板、输入和输出、错误和异常、类和标准库详解等方面的知识技巧。同时后附的手册可以方便你的查询。
-
setup里放所有前置依赖:导入、变量定义、对象构造 - 避免在
stmt里写import json或s = '{"a": 1}',它们该进setup - 如果用字符串形式调用,
setup和stmt是独立作用域,不能共享变量名(除非用globals)
错误示例:
timeit.timeit('json.loads(s)', number=100000)——s 和 json 都未定义,会报 NameError。
用 timeit.repeat() 而不是多次调用 timeit.timeit()
单次 timeit.timeit() 结果波动大,尤其在有 GC、CPU 频率调节、后台进程干扰时。这不是精度问题,是测量方法本身不可靠。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 默认用
timeit.repeat(repeat=5, number=100000),取返回列表最小值(排除抖动峰值) - 别手动循环调用
timeit.timeit()五次再求平均——平均值会掩盖异常延迟,最小值才反映真实下限 -
repeat比number更影响稳定性:增大number只是延长单次运行,但repeat是真正重启计时上下文
命令行 timeit 怎么传带参数的函数
命令行模式不支持闭包或局部变量,想测 functools.partial 或带默认参数的函数,容易卡在语法或作用域上。
实操建议:
- 用
-s(setup)预定义函数和参数:python -m timeit -s "from functools import partial; from math import sqrt; f = partial(sqrt, 123)" "f()"
- 避免在命令行 stmt 中写 lambda 或内联表达式(如
"(lambda x: x**2)(5)"),编译开销混入结果 - 如果函数需要模块级状态(如缓存),命令行模式很难模拟,优先改用脚本内调用
timeit 测的是纯 CPU 时间,不代表真实场景性能
timeit 默认关闭 GC、禁用线程切换、反复执行同一段代码——这跟 Web 请求、文件读写、数据库查询等 I/O 密集型场景完全脱节。
实操建议:
- 测 I/O 操作(如
open()、requests.get())基本没意义:网络延迟、磁盘缓存、连接复用都会让结果失真 - 对含
print()、logging、time.sleep()的代码,timeit测出的只是“触发开销”,不是实际耗时 - 真正要对比算法性能?确保两者都纯计算、无副作用、输入规模一致;否则不如用
cProfile看真实调用栈
最容易被忽略的一点:timeit 的 number 不是“执行次数”而是“语句重复执行次数”,它不展开函数内部逻辑——你看到快,可能只是因为函数体短,而不是算法优。









