Skip to main content
 首页 » 编程设计

python之循环结构中的加速

2025年05月04日8Leo_wl

当涉及到以不同方式构建列表时,我注意到一些有趣的行为。 .append 比 list-comprehensions 花费的时间长,而 list-comprehensions 比 map 花费的时间长,如下面的实验所示:

def square(x): return x**2 
 
def appendtime(times=10**6): 
  answer = [] 
  start = time.clock() 
  for i in range(times): 
    answer.append(square(i)) 
  end = time.clock() 
  return end-start 
 
def comptime(times=10**6): 
  start = time.clock() 
  answer = [square(i) for i in range(times)] 
  end = time.clock() 
  return end-start 
 
def maptime(times=10**6): 
  start = time.clock() 
  answer = map(square, range(times)) 
  end = time.clock() 
  return end-start 
 
for func in [appendtime, comptime, maptime]: 
  print("%s: %s" %(func.__name__, func())) 

python 2.7:

appendtime: 0.42632 
comptime: 0.312877 
maptime: 0.232474 

python 3.3.3:

appendtime: 0.614167 
comptime: 0.5506650000000001 
maptime: 0.57115 

现在,我很清楚 python 2.7 中的 range 构建了一个列表,所以我明白了为什么 python 2.7 和 3.3 中相应函数的时间存在差异。我比较关心的是append、list-comprehension和map的相对时间差。

起初,我认为这可能是因为 map 和列表推导可以让解释器知道结果列表的最终大小,这将允许解释器 malloc 一个足够大的 C 数组在引擎盖下存储列表。按照这个逻辑,列表理解和 map 应该花费几乎相同的时间。
然而,计时数据显示,在 python 2.7 中,listcomps 的速度是 append 的 ~1.36 倍,而 map 的速度是 listcomps 的~1.34 倍。
更奇怪的是,在 python 3.3 中,listcomps 的速度是 append 的 ~1.12 倍,而 map 实际上比 listcomps 慢。

显然,map 和 listcomps 不“按照相同的规则进行游戏”;很明显,map 利用了 listcomps 所没有的东西。
谁能阐明这些时序值差异背后的原因?

请您参考如下方法:

首先,在 python3.x 中,map 返回一个 iterable,而不是一个列表,所以这解释了 50kx 的加速。为了让它成为一个公平的时机,在 python3.x 中你需要 list(map(...))。

其次,.append会比较慢,因为每次循环,解释器都需要查找列表,然后需要查找append函数列表。这个额外的 .append 查找不需要与 list-comp 或 map 一起发生。

最后,通过列表推导,我相信函数 square 需要在循环的每个回合中查找。使用 map 时,它只会在您调用 map 时查找,这就是为什么如果您在列表理解中调用函数,map 通常会更快。请注意,列表推导通常用 lambda 函数击败 map。