为什么if True比if 1慢?

38

为什么Python中if Trueif 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. 根据Mr.Sylvain Defresne在这个问题中的回答,所有的值都会被隐式转换为bool类型并且再进行检查。那么为什么if Trueif 1慢?
  2. 即使只有return语句不同,为什么test3test1慢?
  3. 像问题2一样,但为什么test4test2稍微快一点

注意:我运行了timeit三次并取得平均结果,然后将时间和代码发布在此处。

这个问题与如何进行微基准测试无关(尽管我在这个示例中进行了基本的测试),而是关于为什么检查'True'变量比常量慢的原因。


我认为你的测试太小了。而且三次运行的平均值还不够:p - keyser
我明白 :) 即使测试用例太基础,也难以想象。 但是,我们需要从某个地方开始对吧 :) - thiruvenkadam
可能是微基准测试需要运行多长时间?的重复问题。 - user177800
@JarrodRoberson 感谢提供链接 :-) 但是,我的问题与通用微基准测试无关。它是关于为什么使用关键字检查布尔值比检查常量要慢的问题。 - thiruvenkadam
1
True 打出来要比数字 1 多打 4 倍时间。 - user9008839
2个回答

43

TrueFalsePython 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%以内,是可以接受的。


7
尝试运行代码True,False=False,True - Kabie

21

字节码反汇编使差异明显。

>>> 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所提到的,在Python 2中,TrueFalse是全局变量。有很多方法可以访问它们。

>>> 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 更加昂贵。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接