为什么如果True比1慢?

时间:2013-08-08 10:42:10

标签: python performance if-statement boolean timeit

为什么if True比Python中的if 1慢? if True不应该比if 1更快吗?

我正在尝试学习timeit模块。从基础开始,我尝试了这些:

>>> def test1():
...     if True:
...         return 1
...     else:
...         return 0

>>> print timeit("test1()", setup = "from __main__ import test1")
0.193144083023


>>> def test2():
...     if 1:
...         return 1
...     else:
...         return 0

>>> print timeit("test2()", setup = "from __main__ import test2")
0.162086009979


>>> def test3():
...     if True:
...             return True
...     else:
...             return False

>>> print timeit("test3()", setup = "from __main__ import test3")
0.214574098587

>>> def test4():
...     if 1:
...             return True
...     else:
...             return False

>>> print timeit("test4()", setup = "from __main__ import test4")
0.160849094391

我对这些事感到困惑:

  1. 根据Sylvain Defresne先生在this question中的回复,先将所有内容隐式转换为bool,然后再进行检查。那么为什么if Trueif 1慢?
  2. 为什么test3慢于test1,即使只有return值不同?
  3. 与问题2类似,但为什么test4test2 更快
  4. 注意:我运行了timeit三次,取了结果的平均值,然后将这些时间与代码一起发布。

    这个问题与如何进行微基准测试无关(我在这个例子中做了但我也明白它太基础了)但是为什么检查'True'变量比常数慢。

2 个答案:

答案 0 :(得分:29)

TrueFalse不是Python 2中的关键字。

他们必须在运行时解决。这已在Python 3

中更改

Python 3上的相同测试:

>>> timeit.timeit('test1()',setup="from __main__ import test1", number=10000000)
2.806439919999889
>>> timeit.timeit('test2()',setup="from __main__ import test2", number=10000000)
2.801301520000038
>>> timeit.timeit('test3()',setup="from __main__ import test3", number=10000000)
2.7952816800000164
>>> timeit.timeit('test4()',setup="from __main__ import test4", number=10000000)
2.7862537199999906

时间误差为1%,这是可以接受的。

答案 1 :(得分:18)

Bytecode反汇编明显不同。

>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             

  3           7 LOAD_CONST               1 (1)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  5          12 LOAD_CONST               2 (0)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

正如Kabie所提到的,TrueFalse是Python 2中的全局变量。很多东西都在继续访问它们。

>>> dis.dis(test2)
  3           0 LOAD_CONST               1 (1)
              3 RETURN_VALUE        

Python编译器能够将1识别为一个持续“真实”的表达并优化冗余条件!

>>> dis.dis(test3)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             

  3           7 LOAD_GLOBAL              0 (True)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  5          12 LOAD_GLOBAL              1 (False)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

test1几乎相同,还有一个LOAD_GLOBAL

>>> dis.dis(test4)
  3           0 LOAD_GLOBAL              0 (True)
              3 RETURN_VALUE        

请参阅test2。但LOAD_GLOBALLOAD_CONST贵一点。