如何在传递变量给函数时使用python timeit?

84 投票
5 回答
46535 浏览
提问于 2025-04-17 02:53

我在使用timeit的时候遇到了一些困难,想问问有没有人能给点建议。

简单来说,我有一个函数(我会给它传一个值),我想测试一下这个函数的运行速度,所以我写了这个:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(superMegaIntenseFunction(10))
    print t.timeit(number=1)

但是当我运行它的时候,出现了一些奇怪的错误,像是来自timeit模块的错误:

ValueError: stmt is neither a string nor callable

如果我单独运行这个函数,它是没问题的。问题出在我把它放进timeit模块里时,就出现了错误(我试过用双引号和不用双引号,结果都是一样的)。

如果能给点建议就太好了!

谢谢!

5 个回答

20

你应该传递一个字符串。也就是说,

t = Timer('superMegaIntenseFunction(10)','from __main__ import superMegaIntenseFunction')
24

Timer(superMegaIntenseFunction(10)) 的意思是“先调用 superMegaIntenseFunction(10),然后把结果传给 Timer”。这显然不是你想要的。Timer 期待的是一个可调用的东西(听起来就是可以被调用的东西,比如一个函数),或者一个字符串(这样它可以把字符串里的内容当作 Python 代码来理解)。Timer 的工作原理是反复调用这个可调用的东西,看看需要多长时间。

Timer(superMegaIntenseFunction) 这个写法是可以通过类型检查的,因为 superMegaIntenseFunction 是可调用的。但是,Timer 不知道该给 superMegaIntenseFunction 传什么值。

解决这个问题的简单方法是使用一个包含代码的字符串。我们需要给代码传递一个“setup”参数,因为这个字符串是在一个新的环境中“被解释为代码”的——它无法访问相同的 globals,所以你需要运行另一段代码来让定义可用——可以参考 @oxtopus 的回答。

通过 lambda(就像 @Pablo 的回答中提到的),我们可以把参数 10 绑定到调用 superMegaIntenseFunction 上。我们所做的就是创建另一个不需要参数的函数,然后用 10 调用 superMegaIntenseFunction。这就像你用 def 创建了另一个这样的函数,只不过这个新函数没有名字(因为它不需要名字)。

139

把它变成可以调用的:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(lambda: superMegaIntenseFunction(10))
    print(t.timeit(number=1))

应该可以正常工作

撰写回答