首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >timeit ValueError: stmt既不是字符串也不是可调用的

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

Stack Overflow用户
提问于 2019-01-10 19:33:36
回答 6查看 18.6K关注 0票数 18

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

我定义了一个简单的函数add。当我传递两个字符串参数时,timeit可以工作。但是,当我传递ValueError: stmt is neither a string nor callable两个int参数时,它会引发int

代码语言:javascript
运行
复制
>>> 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

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

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 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的表达式:

代码语言:javascript
运行
复制
>>> 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()函数、ab,因此您需要使用第二个参数,即安装字符串来访问它。可以使用from __main__ import add, a, b导入add函数对象:

代码语言:javascript
运行
复制
timeit.timeit('add(a, b)', 'from __main__ import add, a, b')

现在,您获得了更有意义的结果:

代码语言:javascript
运行
复制
>>> 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

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

票数 27
EN

Stack Overflow用户

发布于 2020-10-06 10:12:47

使用string版本add返回一个字符串,它可以计算这个字符串的时间。因此,"12“是一个有效的python表达式,而3则不是。

代码语言:javascript
运行
复制
timeit.timeit("12") # works
timeit.timeit(3) # does not

使用timeit的最佳方法是用lambda包装要测试的函数:

代码语言:javascript
运行
复制
timeit.timeit(lambda: add(1,2))

这比处理字符串更优雅,更容易出错。

请注意,lambda为每个调用引入了一些轻微的开销。如果您的函数执行任何远程复杂的操作,这将是可以忽略不计的,但是对于非常简单的代码段(如"a+b"),开销将产生重大影响。

票数 19
EN

Stack Overflow用户

发布于 2019-01-10 19:34:53

我的问题是为什么参数类型在这里很重要?

函数参数在调用函数之前被完全计算。这意味着当你这样做:

代码语言:javascript
运行
复制
timeit.timeit(add(a,b))

然后,在使用add(a,b)之前已经计算了timeit。所以,它没有时间。

当a和b是数字字符串时,timeit.timeit(add(a,b))“工作”的原因只是一个愚蠢的原因:它为'12'的计算计时。调用add('1', '2')的结果恰好是这里的有效字符串。timeit编译它,并假设您希望对字面整数12的计算时间。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54135771

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档