生成器不该这么用

Python生成器不该这么用

最近在知乎上有人误解了Python生成器的使用,在这里我们来统一探讨下它这么用对不对。

举一个例子,编写一个函数计算一串数字里所有偶数的个数,其实是很简单的问题,但是有些人是用生成器这么写的:

In [66]: def f1(x):
   ....:     return sum(c in '02468' for c in str(x))
   ....: 
In [68]: x = int('1234567890'*50)
In [69]: %timeit f1(x)
10000 loops, best of 5: 52.2 µs per loop

生成器这么用其实是速度最慢的一种做法,花费了52微秒。我们来看看如果我改成列表解析式会怎么样:

In [67]: def f2(x):
  ....:     return sum([c in '02468' for c in str(x)])
  ....:  
In [70]: %timeit f2(x)
10000 loops, best of 5: 40.5 µs per loop 

你看,这个加速非常地明显,仅花费了40.5微秒

而且还能进一步改进, 如果我们改变之前定义的f2,让它在列表解析式后判断数字是否为偶数,是偶数才会成为最终生成的列表中的一员,这样有另一个加速:

In [71]: def f3(x):
   ....:     return sum([True for c in str(x) if c in '02468'])
   ....: 
In [72]: %timeit f3(x)
10000 loops, best of 5: 34.9 µs per loop


34.9微秒,Perfect! 不仅如此,还能继续加速!sum对于整数有一个快速路径,但是这个快速路径只激活类型为int的变量. bool不行,因此我们把True改成1,能再加一次速!

In [73]: def f4(x):
   ....:     return sum([1 for c in str(x) if c in '02468'])
   ....: 
In [74]: %timeit f4(x)
10000 loops, best of 5: 33.3 µs per loop

​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注