我在Python中玩过timeit
,遇到了一个奇怪的问题。
我定义了一个简单的函数add
。当我传递timeit
两个字符串参数时,add
起作用。但是,当我通过ValueError: stmt is neither a string nor callable
传递两个add
参数时,它将引发int
。
>>> import timeit
>>> def add(x,y):
... return x + y
...
>>> a = '1'
>>> b = '2'
>>> timeit.timeit(add(a,b))
0.01355926995165646
>>> a = 1
>>> b = 2
>>> timeit.timeit(add(a,b))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/anaconda/lib/python3.6/timeit.py", line 233, in timeit
return Timer(stmt, setup, timer, globals).timeit(number)
File "/anaconda/lib/python3.6/timeit.py", line 130, in __init__
raise ValueError("stmt is neither a string nor callable")
ValueError: stmt is neither a string nor callable
为什么参数类型在这里根本不重要?
答案 0 :(得分:5)
我的问题是为什么参数类型在这里很重要?
在调用函数之前,将对函数参数进行全面评估。这就是说,当您这样做时:
timeit.timeit(add(a,b))
然后在使用add(a,b)
之前已经计算出timeit
。因此,它没有时间。
当a和b是数字字符串时,timeit.timeit(add(a,b))
“起作用”的原因只是一个愚蠢的原因:它为'12'
的求值计时。调用add('1', '2')
的结果恰好是一个有效的Python代码字符串。 timeit
对其进行编译,并假设您想计时字面整数12的求值时间。
答案 1 :(得分:3)
您的错误是假设Python将表达式add(a, b)
传递给timeit()
。并非如此,add(a, b)
不是字符串,而是一个表达式,因此Python会执行 add(a, b)
并传递该调用的结果转到timeit()
呼叫。
因此对于add('1', '2')
,结果是'12'
,是一个字符串。将字符串传递到timeit()
很好。但是add(1, 2)
是12
,是整数。 timeit(12)
给您一个例外。当然,计时'12'
并不是那么有趣,但这是一个有效的Python表达式,产生整数值12:
>>> import timeit
>>> def add(x,y):
... return x + y
...
>>> a = '1'
>>> b = '2'
>>> add(a, b)
'12'
>>> timeit.timeit('12')
0.009553937998134643
>>> a = 1
>>> b = 2
>>> add(a, b)
12
>>> timeit.timeit(12)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/.../lib/python3.7/timeit.py", line 232, in timeit
return Timer(stmt, setup, timer, globals).timeit(number)
File "/.../lib/python3.7/timeit.py", line 128, in __init__
raise ValueError("stmt is neither a string nor callable")
ValueError: stmt is neither a string nor callable
这完全是正常现象;否则,如何将一个函数的结果直接传递给另一个函数? timeit.timeit()
是另一个Python函数,没什么特别的,它会禁用表达式的常规求值。
您想要的是将带有表达式的字符串传递给timeit()
。 timeit()
无权访问您的add()
函数,a
或b
,因此您需要使用第二个参数(设置字符串)为它提供访问权限。您可以使用from __main__ import add, a, b
来导入ad
函数对象:
timeit.timeit('add(a,b)', 'from __main__ import add, a, b')
现在您可以获得更有意义的结果:
>>> import timeit
>>> def add(x,y):
... return x + y
...
>>> a = '1'
>>> b = '2'
>>> timeit.timeit('add(a,b)', 'from __main__ import add, a, b')
0.16069997000158764
>>> a = 1
>>> b = 2
>>> timeit.timeit('add(a,b)', 'from __main__ import add, a, b')
0.10841095799696632
因此,添加整数比添加字符串快。您可能想尝试使用不同大小的整数和字符串,但是添加整数将保持更快的结果。
答案 2 :(得分:1)
使用字符串版本add返回一个字符串,该字符串可以评估其时间。因此,“ 12”是有效的python表达式,而3则不是。
timeit.timeit("12") # works
timeit.timeit(3) # does not
使用timeit的最佳方法是使用lambda扭曲要测试的功能:
timeit.timeit(lambda: add(1,2))
这比弄乱字符串要优雅得多。我真的不明白为什么所有示例都使用字符串。
答案 3 :(得分:0)
解决类型“问题”的另一种方法是将函数的结果作为字符串传递!
timeit.timeit('%s'%(add(1,2)))
or
timeit.timeit(f'{add(1,2)}')