优化Python的执行速度
1. 尽量不要使用全局变量,把代码块封装成函数,看下面的代码
import time
# 全局代码块
start = time.perf_counter()
for i in range(100000000):
i += 1
print('global cost time:',time.perf_counter()-start)
def fun():
for j in range(100000000):
j += 1
# 函数局部代码块
start = time.perf_counter()
fun()
print('local cost time',time.perf_counter()-start)
执行结果如下:
global cost time: 18.455917499999998
local cost time: 9.9030749
分析:
整整快了两倍!这是因为局部变量的检索速度比全局变量快。
2. 尽可能去掉属性访问
每一次使用点 (.) 操作符来访问属性的时候会带来额外的开销。它会触发特定的方法,比如 getattribute() 和 getattr() ,这些方法会进行字典操作操作。
import math
import time
def compute_roots_original(nums):
result = []
for n in nums:
result.append(math.sqrt(n))
return result
def compute_roots_optimized(nums):
result = []
sqrt = math.sqrt
result_append = result.append
for n in nums:
result_append(sqrt(n))
return result
nums = range(1000000)
start = time.perf_counter()
for n in range(100):
r = compute_roots_original(nums)
print('compute_roots_original cost time',time.perf_counter()-start)
start = time.perf_counter()
for n in range(100):
r = compute_roots_optimized(nums)
print('compute_roots_optimized cost time',time.perf_counter()-start)
compute_roots_original cost time: 51.4366062
compute_roots_optimized cost time: 37.177331200000005
分析:
可以看出速度还是有提升的,比如在一个类中,会循环访问对象的self.name属性,可以考虑使用name = self.name并将这段代码放在循环体之外,循环体内直接使用name即可。
3. 在创建字典的时候使用d = {},而不是 d= dict(),看以下代码
import timeit
print("use d={},time cost:",timeit.timeit('d={}'))
print("use d=dict(),time cost:",timeit.timeit('d=dict()'))
use d={},time cost: 0.0328155
use d=dict(),time cost: 0.14066270000000003
可以看出,速度提升还是很明显的,这在创建大量字典的时候可能用的上。
4. 使用()进行列表推导而不是[]
import time
start = time.perf_counter()
for i in (x*x for x in range(10000000)):
...
print('() cost time:',time.perf_counter()-start)
start = time.perf_counter()
for j in [x*x for x in range(10000000)]:
...
print('[] cost time:',time.perf_counter()-start)
() cost time: 1.4474916000000002
[] cost time: 2.176057
结果如上,打印 (x*x for x in range(10000000)可以发现它是一个生成器,生成器只有在需要某个元素的时候才会生成这个元素,占用的内存很小,而list会直接生成所有的元素,当数据量很大的时候,会占用很大的内存。