zoukankan      html  css  js  c++  java
  • Python while 1 和 while True 速度比较

     

    References

    http://legacy.python.org/dev/peps/pep-0285/
    http://stackoverflow.com/questions/3815359/while-1-vs-for-whiletrue-why-is-there-a-difference

    本文内容遵从CC3.0版权协议,转载请注明:转自Pythoner

    本文链接地址:Python天坑系列(一):while 1比while True更快?

    1. 前提

      1.1 bool是int的子类

    根据PEP285中Review部分第6条所述,bool类是从int类继承而来的,这样可以极大的简化实现(C代码中调用PyInt_Check()的地方仍将继续工作)。

      1.2 Python2中True/False不是关键字,但Python3中是

    我们可以导入keyword模块,来查看关键字:

    >>> import keyword
    >>> keyword.kwlist
    ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']

    而在Python3中,关键字中添加了True/False/None。

    由于Python2中True/False不是关键字,因此我们可以对其进行任意的赋值:

    >>> (1==1) == True
    True
    >>> True = "abc"
    >>> (1==1) == True
    False

    2. True + True = 2

    由于bool是继承自int的子类,因此为了保证向下兼容性,在进行算术运算中,True/False会被当作int值来执行。

    >>> True + True
    2
    >>> True - True
    0
    >>> True * True
    1
    >>> (True + True) > 1
    True
    >>> True + 5
    6
    >>> False + 1
    1
    >>> 1 / False
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: integer division or modulo by zero

    3. While 1比While True快?

    首先来看一个比较while 1和while True循环的脚本,两个函数中,除了1和True的区别之外,其他地方完全相同。

    import timeit
    def while_one():
        i = 0 
        while 1:
            i += 1
            if i == 10000000:
                break
    
    def while_true():
        i = 0 
        while True:
            i += 1
            if i == 10000000:
                break
    
    if __name__ == '__main__':
        wone = timeit.timeit(while_one,"from __main__ import while_one",number=3)
        wt = timeit.timeit(while_true,"from __main__ import while_true",number=3)
        print "while_one: %s
    while_true: %s" % (wone,wt)

    执行结果:

    while_one: 0.937821149826
    while_true: 1.39164209366

    可以看出wihle 1的执行时间约为while True的2/3   

    那么,这是为什么呢?

    其实这就是前提中提到的关键字的问题。由于Python2中,True/False不是关键字,因此我们可以对其进行任意的赋值,这就导致程序在每次循环时都需要对True/False的值进行检查;而对于1,则被程序进行了优化,而后不会再进行检查。

    我们可以通过dis模块来查看while_one和while_true的字节码,下面的程序是对刚才的程序进行了一定的简化后的版本

    import dis
    def while_one():
        while 1:
            pass
    
    def while_true():
        while True:
            pass
    if __name__ == "__main__":
        print "while_one
    "
        dis.dis(while_one)
    
        print "while_true
    "
        dis.dis(while_true)

    执行的结果是:

     

    while_one
    
      6           0 SETUP_LOOP               3 (to 6)
    
      7     >>    3 JUMP_ABSOLUTE            3
            >>    6 LOAD_CONST               0 (None)
                  9 RETURN_VALUE        
    while_true
    
     10           0 SETUP_LOOP              10 (to 13)
            >>    3 LOAD_GLOBAL              0 (True)
                  6 POP_JUMP_IF_FALSE       12
    
     11           9 JUMP_ABSOLUTE            3
            >>   12 POP_BLOCK           
            >>   13 LOAD_CONST               0 (None)
                 16 RETURN_VALUE  
    

    可以看出,正如上面所讲到的,在while True的时候,字节码中多出了几行语句,正是这几行语句进行了True值的检查。

    而在Python3中,由于True/False已经是关键字了,不允许进行重新赋值,因此,其执行结果与while 1不再有区别(好吧,我这没有Python3的环境,就不去验证了,网上有人验证过了)。但是由于Python2的使用十分广泛,因此大家不得不注意这个可能会降低性能的地方。

     

    4. if x == True: 还是 if x:

    在PEP285中,还提到了这两种写法的比较。PEP285中认为,==具有传递性,a==b, b==c会被化简为a==c。也就是说,如果选择前一种写法的话,6和7在if语句中都应该被认为是真值,那么就会造成6==True==7,被化简为6==7的问题,因此后一种写法才是正确的。

    现在,让我们偏个题,假设x就是True,那么程序的执行效率又如何呢?

    import timeit
    
    def if_x_equal_true():
        x = True
        if x == True:
            pass
    
    def if_x():
        x = True
        if x:
            pass
    
    if __name__ == "__main__":
        if1 = timeit.timeit(if_x_equal_true,"from __main__ import if_x_equal_true",number = 1000000)
        if2 = timeit.timeit(if_x,"from __main__ import if_x",number = 1000000)
    
        print "if_x_equal_true: %s
    if_x: %s" % (if1,if2)

    执行结果:

    if_x_equal_true: 0.127066850662
    if_x: 0.0872008800507

     

    让我们再来看看字节码(程序未作修改,dis的使用方式同上,因此不再给出程序):

    if_x_equal_true
    
      7           0 LOAD_GLOBAL              0 (True)
                  3 STORE_FAST               0 (x)
    
      8           6 SETUP_LOOP              16 (to 25)
            >>    9 LOAD_FAST                0 (x)
                 12 LOAD_GLOBAL              0 (True)
                 15 COMPARE_OP               2 (==)
                 18 POP_JUMP_IF_FALSE       24
    
      9          21 JUMP_ABSOLUTE            9
            >>   24 POP_BLOCK           
            >>   25 LOAD_CONST               0 (None)
                 28 RETURN_VALUE        
    if_x
    
     12           0 LOAD_GLOBAL              0 (True)
                  3 STORE_FAST               0 (x)
    
     13           6 SETUP_LOOP              10 (to 19)
            >>    9 LOAD_FAST                0 (x)
                 12 POP_JUMP_IF_FALSE       18
    
     14          15 JUMP_ABSOLUTE            9
            >>   18 POP_BLOCK           
            >>   19 LOAD_CONST               0 (None)
                 22 RETURN_VALUE        
    

      

    可以清晰的看到第9行比第14行,多出了检查True值和进行比较的操作。

    也就是说,不论从遵循PEP的规范,还是执行效率,或者程序的简洁性来说,我们都应该使用if x:,而不是if x == True:来进行比较。同理,那些if x is not None:之类的语句也应当被简化为if x:(如果要比较的是非值,而不必须是None的话)。

     

     

  • 相关阅读:
    2018 蓝桥杯省赛 B 组模拟赛(一)-年龄
    在win10系统下安装和卸载Ubuntu系统(为了搞双系统)的各种办法
    2018 CCPC 中国大学生程序设计竞赛-网络选拔赛 1004(D题 )Find Integer(三角函数+费马大定理)
    HDU(杭州电子科技大学) 2614 Beat (BFS写法)
    SQL server用到的SQL语句备份下
    【SQL Server】SQL触发器经验详解
    SQL SERVER 语句大全
    sqlserver 触发器实例代码
    触发器deleted 表和 inserted 表详解
    SQL server触发器中 update insert delete 分别给写个例子被。
  • 原文地址:https://www.cnblogs.com/zhanhg/p/4383576.html
Copyright © 2011-2022 走看看