首页 > 解决方案 > timeit ValueError:stmt 既不是字符串也不是可调用的

问题描述

timeit在 Python 中玩过,遇到了一个奇怪的问题。

我定义了一个简单的函数addtimeit当我传递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

为什么参数类型在这里很重要?

标签: pythoncallabletimeit

解决方案


您的错误是假设 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 的有效 Python 表达式:

>>> 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()函数aor 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

所以添加整数比添加字符串要快。您可能想尝试使用不同大小的整数和字符串,但添加整数仍然是更快的结果。


推荐阅读