前言
在Python这门语言中,生成器毫无疑问是最有用的特性之一。与此同时,也是使用的最不广泛的Python特性之一。究其原因,主要是因为,在其他主流语言里面没有生成器的概念。正是由于生成器是一个“新”的东西,所以,它一方面没有引起广大工程师的重视,另一方面,也增加了工程师的学习成本,最终导致大家错过了Python中如此有用的一个特性。
一、何为生成器?
顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 next 方法(python2 是 next)的对象都可以称为迭代器。
Python有两种不同的方式提供生成器:
- 生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
- 生成器表达式: 类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表&oq=类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
二、生成器函数
我们来看一个例子,使用生成器返回自然数的平方(注意返回的是多个值):
def gensquares(N):
for i in range(N):
yield i ** 2
for item in gensquares(5):
print(item)
输出结果:
使用普通函数:
def gensquares(N):
res=[]
for i in range(N):
res.append(i*i)
return res
for item in gensquares(5):
print(item)
可以看出,使用生成器函数代码量更少了。
三、生成器表达式
使用列表推导式,将会一次产生所有结果:
s1=[x**2 for x in range(5)]
print(s1) #输出结果:[0, 1, 4, 9, 16]
将列表推导式的中括号,替换成圆括号,就是一个生成器的表达式:
>>>s1=(x**2+for+x+in+range(5))
>>>s1
>>>generator+object+at+0x00B2EC88>
>>>next(s1)
#0
>>>next(s1)
#1
>>>next(s1)
#4
>>>list(s1)
>#[9,16]
四、再看生成器
前面已经对生成器有了感性的认识,我们以生成器函数为例,再来深入探讨一下Python的生成器:
- 语法上和函数类似: 生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
- 自动实现迭代器协议: 对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常
- 状态挂起: 生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行
五、案例
1.利用生成器生成可以无限取值的斐波拉切函数:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
p = fib()
print([p.next() for i in xrange(101)])
2.生成器处理大日志文本文本:
def find_ip(path):
for line in open(path):
s = line.find('"Sogou web spider')
if s >= 0:
yield line[:s].strip()
p = find_ip("bigfile.txt")
p = list(set(list(p)))
for item in p:
print item
print(time.time() - start_time, "seconds")
总结
本文深入浅出地介绍了Python中,一个容易被大家忽略的重要特性,即Python的生成器。在学习中,充分利用Python生成器,不但能够减少内存使用,还能够提高代码可读性。掌握生成器也是Python高手的标配。希望本文能够帮助大家理解Python的生成器。