关于python:为什么if true比if 1慢?

Why is if True slower than if 1?

为什么在python中if Trueif 1慢?难道if True不应该比if 1快吗?

我试着学习timeit模块。从基础开始,我尝试了以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
>>> 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

我对这些事情感到困惑:

  • 根据Sylvain Defresne先生在这个问题上的回答,所有的东西都被隐式转换成一个bool,然后进行检查。那么,为什么if Trueif 1慢?
  • 为什么即使只有return值不同,test3test1慢?
  • 就像问题2,但是为什么test4test2快一点?
  • 注意:我运行timeit三次,取结果的平均值,然后将时间和代码一起发布在这里。

    这个问题不涉及如何进行微观基准测试(我在这个例子中做过,但我也理解这太基本了),但为什么检查"真"变量比常量慢。


    在python 2中,TrueFalse不是关键字。

    它们必须在运行时解析。这在python 3中已经改变了

    在python 3上进行相同的测试:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> 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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> 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中的全局。很多东西都是用来访问它们的。

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

    python编译器能够将1识别为一个持续的"真实"表达式,并将多余的条件优化掉!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> 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

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

    test2。但是LOAD_GLOBALLOAD_CONST贵一些。