为什么“不”比Python中的“bool()”更快(或者Python函数与语句的速度)?

时间:2014-08-31 16:57:58

标签: python

前几天我做了一个有趣的观察。我正在尝试各种方法来获得"真实性"一个对象和每个对象的速度,我注意到not bool更快。

>>> bool([5, 6, 7])
True
>>> bool([])
False
>>> not not [5, 6, 7]
True
>>> not not []
False
>>> import timeit
>>> from numpy import mean
>>> mean(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10))
0.19072036743164061
>>> mean(timeit.repeat('bool(a)', 'a = []', repeat=10))
0.18562331199645996
>>> mean(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10))
0.072056698799133304
>>> mean(timeit.repeat('not not a', 'a = []', repeat=10))
0.073475956916809082
>>> mean(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10))
0.043941426277160647
>>> mean(timeit.repeat('not a', 'a = []', repeat=10))
0.044287109375000001

我们可以看到使用bool函数比使用not语句慢得多,即使最终它们做同样的事情(返回对象的布尔状态)。现在,我们都被告知在Python中,函数开销很大,但由于以下原因,我并不期望这种差异:

  • bool()是一个内置函数,意味着它是用C语言编写的,我原本预计这会有一个相当低的开销
  • 在这两种情况下,Python必须评估"真实性"内部的对象(我想他们会在内部使用相同的C例程来执行此操作)
    • 事实上,not必须返回对象"真实性"的逻辑相反,所以理论上它正在做更多的工作(但也许有一个实现细节可以解决这个问题)

在我看来,因为两个函数基本上都在做同样的事情,所有额外的时间必须来自函数开销。如果是这种情况,为什么声明能够避免与函数相比如此多的开销?如果不是开销,为什么bool()not慢得多?


更新:除了平均值之外,这里也是最短时间。

>>> min(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10))
0.18180489540100098
>>> min(timeit.repeat('bool(a)', 'a = []', repeat=10))
0.1821761131286621
>>> min(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10))
0.0707249641418457
>>> min(timeit.repeat('not not a', 'a = []', repeat=10))
0.07100605964660645
>>> min(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10))
0.04264092445373535
>>> min(timeit.repeat('not a', 'a = []', repeat=10))
0.04357004165649414

2 个答案:

答案 0 :(得分:3)

(这不应该是答案,只是文档):这些是给定表达式的字节码序列:

bool(a)

1           0 LOAD_NAME                0 (bool)
            3 LOAD_NAME                1 (a)
            6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
            9 RETURN_VALUE

not a

1           0 LOAD_NAME                0 (a)
            3 UNARY_NOT
            4 RETURN_VALUE

not not a

1           0 LOAD_NAME                0 (a)
            3 UNARY_NOT
            4 UNARY_NOT
            5 RETURN_VALUE

答案 1 :(得分:0)

所有函数调用都有很大的开销 - 毕竟你创建了一个新的堆栈框架来保存你的呼叫中的新本地人。

如果这是一个更昂贵的操作,那么开销就会在噪音中丢失。因为你正在看这样一个微不足道的操作,所以它很突出。