在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)
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
>>> dis.dis(global_var)
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程序更快的原因了。所以,养成在进入大规模的循环之前,用局部变量还是替代全局变量的习惯,还是相当有必要的。