我在Python中玩timeit
,遇到了一个奇怪的问题。
我定义了一个简单的函数add
。当我传递两个字符串参数时,timeit
可以工作。但是,当我传递ValueError: stmt is neither a string nor callable
两个int
参数时,它会引发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
为什么参数类型在这里很重要?
发布于 2019-01-10 20:14:28
您的错误是假设Python将表达式add(a, b)
传递给timeit()
。情况并非如此,add(a, b)
不是一个字符串,它是一个表达式,因此Python将执行add(a, b)
,并将该调用的结果传递给timeit()
调用。
所以对于add('1', '2')
,结果是'12'
,一个字符串。将字符串传递给timeit()
是可以的。但是add(1, 2)
是3
,一个整数。timeit(3)
给出了一个例外。当然,计时'12'
并不是那么有趣,但它是一个有效的生成整数值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)
3
>>> timeit.timeit(3)
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
导入add
函数对象:
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
因此,添加整数比添加字符串更快。您可能想尝试使用不同大小的整数和字符串,但是添加整数仍然是更快的结果。
发布于 2020-10-06 10:12:47
使用string版本add返回一个字符串,它可以计算这个字符串的时间。因此,"12“是一个有效的python表达式,而3则不是。
timeit.timeit("12") # works
timeit.timeit(3) # does not
使用timeit的最佳方法是用lambda包装要测试的函数:
timeit.timeit(lambda: add(1,2))
这比处理字符串更优雅,更容易出错。
请注意,lambda为每个调用引入了一些轻微的开销。如果您的函数执行任何远程复杂的操作,这将是可以忽略不计的,但是对于非常简单的代码段(如"a+b"),开销将产生重大影响。
发布于 2019-01-10 19:34:53
我的问题是为什么参数类型在这里很重要?
函数参数在调用函数之前被完全计算。这意味着当你这样做:
timeit.timeit(add(a,b))
然后,在使用add(a,b)
之前已经计算了timeit
。所以,它没有时间。
当a和b是数字字符串时,timeit.timeit(add(a,b))
“工作”的原因只是一个愚蠢的原因:它为'12'
的计算计时。调用add('1', '2')
的结果恰好是这里的有效字符串。timeit
编译它,并假设您希望对字面整数12的计算时间。
https://stackoverflow.com/questions/54135771
复制相似问题