Why does removing the else slow down my code?

前端 未结 3 1377
清歌不尽
清歌不尽 2021-02-02 10:48

Consider the following functions:

def fact1(n):
    if n < 2:
        return 1
    else:
        return n * fact1(n-1)

def fact2(n):
    if n < 2:
                


        
相关标签:
3条回答
  • 2021-02-02 11:02

    For me, they are virtually the same speed: (Python 2.6.6 on Debian)

    In [4]: %timeit fact1(1)
    10000000 loops, best of 3: 151 ns per loop
    
    In [5]: %timeit fact2(1)
    10000000 loops, best of 3: 154 ns per loop
    

    The byte code is also very similar:

    In [6]: dis.dis(fact1)
      2           0 LOAD_FAST                0 (n)
                  3 LOAD_CONST               1 (2)
                  6 COMPARE_OP               0 (<)
                  9 JUMP_IF_FALSE            5 (to 17)
                 12 POP_TOP             
    
      3          13 LOAD_CONST               2 (1)
                 16 RETURN_VALUE        
            >>   17 POP_TOP             
    
      5          18 LOAD_FAST                0 (n)
                 21 LOAD_GLOBAL              0 (fact)
                 24 LOAD_FAST                0 (n)
                 27 LOAD_CONST               2 (1)
                 30 BINARY_SUBTRACT     
                 31 CALL_FUNCTION            1
                 34 BINARY_MULTIPLY     
                 35 RETURN_VALUE        
                 36 LOAD_CONST               0 (None)
                 39 RETURN_VALUE        
    
    In [7]: dis.dis(fact2)
      2           0 LOAD_FAST                0 (n)
                  3 LOAD_CONST               1 (2)
                  6 COMPARE_OP               0 (<)
                  9 JUMP_IF_FALSE            5 (to 17)
                 12 POP_TOP             
    
      3          13 LOAD_CONST               2 (1)
                 16 RETURN_VALUE        
            >>   17 POP_TOP             
    
      4          18 LOAD_FAST                0 (n)
                 21 LOAD_GLOBAL              0 (fact)
                 24 LOAD_FAST                0 (n)
                 27 LOAD_CONST               2 (1)
                 30 BINARY_SUBTRACT     
                 31 CALL_FUNCTION            1
                 34 BINARY_MULTIPLY     
                 35 RETURN_VALUE        
    

    The only difference is that the version with the else includes code to return None in case control reaches the end of the function body.

    0 讨论(0)
  • 2021-02-02 11:15

    I question the timings. The two functions aren't recursing to themselves. fact1 and fact2 both call fact which isn't shown.

    Once that is fixed, the disassembly (in both Py2.6 and Py2.7) shows that both are running the same op codes except for the name of the recursed into function. The choice of name trigger a small difference in timings because fact1 may insert in the module dictionary with no name collisions while *fact2) may have a hash value that collides with another name in the module.

    In other words, any differences you see in timings are not due to the choice of whether the else-clause is present :-)

    0 讨论(0)
  • 2021-02-02 11:21

    What is happening here is that fact2 has a hash conflict with __name__ in your module globals. That makes the lookup of the global fact2 ever so slightly slower.

    >>> [(k, hash(k) % 32) for k in globals().keys() ]
    [('__builtins__', 8), ('__package__', 15), ('fact2', 25), ('__name__', 25), ('fact1', 26), ('__doc__', 29)]
    

    i.e. The same answer as for Why is early return slower than else? except that there the hash conflict was with __builtins__

    0 讨论(0)
提交回复
热议问题