timeit ValueError: stmt is neither a string nor callable
timeit ValueError: stmt is neither a string nor callable
我在 Python 玩过 timeit
,遇到了一个奇怪的问题。
我定义了一个简单的函数add
。当我传递 add
两个字符串参数时,timeit
起作用。但是当我传递 add
两个 int
参数时它会引发 ValueError: stmt is neither a string nor callable
。
>>> 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
为什么参数类型在这里很重要?
my question is why the parameter type matters here?
函数参数在函数被调用之前被完全评估。这意味着当你这样做时:
timeit.timeit(add(a,b))
那么在使用timeit
之前已经计算了add(a,b)
。所以,它没有时间。
当 a 和 b 是数字字符串时 timeit.timeit(add(a,b))
"works" 的原因只是一个愚蠢的原因:它正在计算 '12'
的时间。这里调用add('1', '2')
的结果恰好是一个有效的Python代码串。 timeit
编译它并假定您想要计算文字整数 12 的计算时间。
您的错误是假设 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()
函数,或 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
所以添加整数比添加字符串更快。您可能想尝试使用不同大小的整数和字符串,但添加整数仍将是更快的结果。
解决类型 "problem" 的另一种方法是将函数的结果作为字符串传递!
timeit.timeit('%s'%(add(1,2)))
or
timeit.timeit(f'{add(1,2)}')
使用字符串版本添加 returns 一个字符串,它可以对其进行评估。所以“12”是一个有效的 python 表达式,而 3 不是。
timeit.timeit("12") # works
timeit.timeit(3) # does not
使用 timeit 的最佳方法是用 lambda 包装要测试的函数:
timeit.timeit(lambda: add(1,2))
这比处理字符串更优雅,更不容易出错。
请注意,lambda 会给每次调用带来一些轻微的开销。如果您的函数做任何远程复杂的事情,这将可以忽略不计,但对于非常简单的片段(如“a+b”),开销将产生重大影响。
我知道这是一个很老的话题,但我发现使用 functools
的类似方法,当您想检查单个函数并传递其参数而不使用字符串或 lambda 时:
import timeit
import functools
def add(x,y):
return x + y
a = 1
b = 2
t = timeit.Timer(functools.partial(add, a, b))
print(t.timeit(10))
输出:
4.565001290757209e-06
对我有用,太棒了!
之前用过datetime,不过这样舒服多了!
我在 Python 玩过 timeit
,遇到了一个奇怪的问题。
我定义了一个简单的函数add
。当我传递 add
两个字符串参数时,timeit
起作用。但是当我传递 add
两个 int
参数时它会引发 ValueError: stmt is neither a string nor callable
。
>>> 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
为什么参数类型在这里很重要?
my question is why the parameter type matters here?
函数参数在函数被调用之前被完全评估。这意味着当你这样做时:
timeit.timeit(add(a,b))
那么在使用timeit
之前已经计算了add(a,b)
。所以,它没有时间。
当 a 和 b 是数字字符串时 timeit.timeit(add(a,b))
"works" 的原因只是一个愚蠢的原因:它正在计算 '12'
的时间。这里调用add('1', '2')
的结果恰好是一个有效的Python代码串。 timeit
编译它并假定您想要计算文字整数 12 的计算时间。
您的错误是假设 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
所以添加整数比添加字符串更快。您可能想尝试使用不同大小的整数和字符串,但添加整数仍将是更快的结果。
解决类型 "problem" 的另一种方法是将函数的结果作为字符串传递!
timeit.timeit('%s'%(add(1,2)))
or
timeit.timeit(f'{add(1,2)}')
使用字符串版本添加 returns 一个字符串,它可以对其进行评估。所以“12”是一个有效的 python 表达式,而 3 不是。
timeit.timeit("12") # works
timeit.timeit(3) # does not
使用 timeit 的最佳方法是用 lambda 包装要测试的函数:
timeit.timeit(lambda: add(1,2))
这比处理字符串更优雅,更不容易出错。
请注意,lambda 会给每次调用带来一些轻微的开销。如果您的函数做任何远程复杂的事情,这将可以忽略不计,但对于非常简单的片段(如“a+b”),开销将产生重大影响。
我知道这是一个很老的话题,但我发现使用 functools
的类似方法,当您想检查单个函数并传递其参数而不使用字符串或 lambda 时:
import timeit
import functools
def add(x,y):
return x + y
a = 1
b = 2
t = timeit.Timer(functools.partial(add, a, b))
print(t.timeit(10))
输出:
4.565001290757209e-06
对我有用,太棒了! 之前用过datetime,不过这样舒服多了!