天天看點

為什麼在Python代碼中使用局部變量會更快

在Python開發中,一個常見的效率優化方法就是在進入循環之前,使用局部變量來替代全局變量。具體的,可以對比下面的兩個函數:

g = 2

def local_var():
    global g
    l = g
    for i in range(100000000):
        i % l
        i + l

def global_var():
    global g
    for i in range(100000000):
        i % g
        i + g           

在這個大循環中,global_var采用了全局變量,而local_var中則先用

l = g

把全局變量放到了局部變量裡。我們可以通過timeit子產品來擷取他們的運作時間,比如

>>> import timeit
>>> timeit.timeit(local_var, number=1, globals=globals())
6.773113199975342
>>> timeit.timeit(global_const, number=1, globals=globals())
6.331308399792761           

如果多次比較,會發現local_var确實明顯要比global_var快一些。為了分析原因,我們可以用dis子產品來分别反編譯這兩個函數的Python中間代碼,放在下面進行對比:

dis.dis(local_var)

dis.dis(global_var)

3           0 LOAD_GLOBAL              0 (g)
              2 STORE_FAST               0 (l)

  4           4 SETUP_LOOP              32 (to 38)
              6 LOAD_GLOBAL              1 (range)
              8 LOAD_CONST               1 (100000000)
             10 CALL_FUNCTION            1
             12 GET_ITER
        >>   14 FOR_ITER                20 (to 36)
             16 STORE_FAST               1 (i)

  5          18 LOAD_FAST                1 (i)
             20 LOAD_FAST                0 (l)
             22 BINARY_MODULO
             24 POP_TOP

  6          26 LOAD_FAST                1 (i)
             28 LOAD_FAST                0 (l)
             30 BINARY_ADD
             32 POP_TOP
             34 JUMP_ABSOLUTE           14
        >>   36 POP_BLOCK
        >>   38 LOAD_CONST               0 (None)
             40 RETURN_VALUE           
3           0 SETUP_LOOP              32 (to 34)
              2 LOAD_GLOBAL              0 (range)
              4 LOAD_CONST               1 (100000000)
              6 CALL_FUNCTION            1
              8 GET_ITER
        >>   10 FOR_ITER                20 (to 32)
             12 STORE_FAST               0 (i)

  4          14 LOAD_FAST                0 (i)
             16 LOAD_GLOBAL              1 (g)
             18 BINARY_MODULO
             20 POP_TOP

  5          22 LOAD_FAST                0 (i)
             24 LOAD_GLOBAL              1 (g)
             26 BINARY_ADD
             28 POP_TOP
             30 JUMP_ABSOLUTE           10
        >>   32 POP_BLOCK
        >>   34 LOAD_CONST               0 (None)
             36 RETURN_VALUE           

比較發現,兩個函數的主要差別在于循環中,local_var使用的是LOAD_FAST指令兒global_var中使用的是LOAD_GLOBAL指令。在Python的解釋器執行中,因為LOAD_GLOBAL要在全局的字典中進行查找,是以LOAD_GLOBAL要比LOAD_FAST慢不少。這應該就是采用局部變量這一優化方法可以讓Python程式更快的原因了。是以,養成在進入大規模的循環之前,用局部變量還是替代全局變量的習慣,還是相當有必要的。