timeit ValueError:stmt既不是字符串也不是可调用的

时间:2019-01-10 19:33:37

标签: python callable timeit

我在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

为什么参数类型在这里根本不重要?

4 个答案:

答案 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()函数,ab,因此您需要使用第二个参数(设置字符串)为它提供访问权限。您可以使用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)}')