1、 什么是生成器
上一讲是迭代器,生成器本质上也是迭代器,生成器不会把结果保存在序列里,但是会保存生成器的状态,每次迭代时返回一个值,知道遇到StopIteration 时结束
2、获得一个生成器
获得生成器有两种方法
2.1 生成器函数
一个函数里出现了yeild关键字,这个函数就不再是普通函数了,而是一个生成器函数,yeild关键字的作用相当于return
#coding=utf-8
def myrange(max):
i = 0
while i < max:
yield i
i += 1
gen = myrange(5)
print type(gen)
2.2 生成器表达式
gen = (x for x in range(5))
print type(gen)
和列表推导式是不是很像呢
3、 生成器的使用
#coding=utf-8
def myrange(max):
i = 0
while i < max:
yield i
i += 1
# 生成器函数
gen = myrange(5)
for item in gen:
print item
# 生成器表达式
gen = (x for x in range(5))
for item in gen:
print item
越是看上面的代码越是觉得眼熟,有没有这种感觉呢看下面的代码
for item in range(5):
print item
不用我写的myrange,直接使用内置函数range可以实现相同的效果,内置函数range返回的是一个列表,实际上使用生成器的地方几乎都可以使用列表,那么问题来了,为什么还要搞出生成器这个东西呢?
很重要的一点是延迟计算
假设要循环1千万次,使用内置函数range 也是可行的,但是前面说到了,range函数返回的是一个列表
lst = range(10000000)
print type(lst)
print len(lst)
这可是实打实的有1千万个元素的列表啊,这得占用多少内存啊,虽然说现在内存不值钱了,但也不能毫无节制的使用,如果使用生成器就不存在这个问题了
gen = myrange(10000000)
此时,内存中并不存在1千万个元素,只是存在一个生成器,现在,还没有使用生成器,生成器就不会生成任何数值
gen = myrange(10000000)
for item in gen:
print item
在for 循环里,每循环一次,生成器生成一个数值,而不是像ragne函数那样一次性生成一个有1千万个元素的列表,这样做大大减少了对内存的使用
4、 生成器和迭代器的关系
其实不必太在意他俩的关系,因为他们存在的意义是不同的,生成器自动实现了迭代器协议,也就是说,生成器是有next方法的,不仅如此,还实现了__iter__方法,生成器既是迭代器,也是可迭代对象
#coding=utf-8
def myrange(max):
i = 0
while i < max:
yield i
i += 1
# 生成器函数
gen = myrange(5)
print gen.next()
i_gen = iter(gen)
print type(i_gen)
for i in i_gen:
print i