什么是生成器
首先,生成器是函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第N次)调用跳转至该函数,而上次调用的所有局部变量都保持不变。
生成器的特点
生成器是一个函数,而且函数的参数都会保留;
迭代到下一次调用时,所使用的参数都是第一次所保留下来的,即在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的。
如何创建一个生产器
创建生产器的关键字为yield
例子:
def gen_test():
print 'start...'
yield 1
print 'continue...'
yield 2
print 'end...'
yield 3
return
for i in gen_test():
print i
打印结果:
start...
1
continue...
2
end...
3
从打印结果可以看到,迭代gen_test时,在生成器内部像是中断了一样,遇到yield即返回迭代的值,下次迭代会从上次的yield开始。
生成器的优势
现实中我们通常会创建一个列表用来循环迭代获取值,但是,受到内存限制,列表容量肯定是优先的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,后面绝大数元素所占用的空间就浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们就可以在循环过程中不断推算出后续的元素。
我们用斐波拉契数列举例:
def fib(count):
a = 0
b = 1
n = 0
while n < count:
yield b
c = b
b = a + b
a = c
n += 1
return
for i in fib(10):
print i
每次yield b的时候,都会中断在此处,跳出生成器函数。
生成器中的方法
常见的生成器方法:close()、send()、throw()
close:代表手动关闭生成器,当调用了close方法后,下个迭代将抛出StopIteration异常。
send:生成器最大的特点是可以接受外部传入的一个变量,并根据变量内容计算结果返回。后续一个重要难点python协程就需要用到它。
例子:
def gen_test_send():
print 'start...'
value = 0
while True:
receive = yield value
if receive == 'end':
break
value = 'get: %s' % receive
gen = gen_test_send()
print gen.send(None)
print gen.send('aaa')
print gen.send(123)
print gen.send('end')
打印结果:
start...
0
get: aaa
get: 123
Traceback (most recent call last):
File "test.py", line 121, in <module>
print gen.send('end')
StopIteration
需要注意的是,在启动生成器函数时只能send(None),如果试图输入其他的值都会得到一个错误提示信息。
throw:用来向生成器函数送入一个一场,可以输入系统定义的异常,或者自定义异常。
展望
python生成器是个很重要的模块,协程编程的基础,为后续学习协程打下基础。