生成器:generator,是一种一边循环一边计算的机制,在传统的函数中,我们可能要从一个函数得到数组列表,而内存容量是有限的,计算出的值到达一定数量时,这样执行效率就会大打折扣。
而生成器函数,如果需要根据规则计算得到多个值,则是每次返回一个值,遇到关键字yield
后然后返回。能更加有效的利用内存,并且可以让调用者先对前面生成的元素进行操作后再继续执行。
生成器有两种形式
生成器表达式:
>>> g = (x*x for x in range(1,10))
>>> g
at 0x10203de60>
生成器函数(斐波拉契数列):
>>> def fib(max):
... n,a,b = 0,0,1
... while n < max:
... yield b
... a,b = b,a+b
... n = n + 1
... return 'done'
只要一个函数中使用了yield
关键字,就可以理解为这个函数就是生成器函数,每一次调用这个生成器函数时,执行到yield
后进入函数中断状态。此时可以理解为这个生成器函数出于挂起状态,下次再调用这个生成器函数时,从上一次返回的yield
处继续往下执行。
>>> g = fib(6)
>>> g
0x10223de60>
变量g
是一个generator
,存放的是一组数值队列,可以通过next()
来取里面的值:
>>> next(g)
1
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
5
>>> next(g)
8
>>> next(g)
Traceback (most recent call last):
File "", line 1, in <module>
StopIteration: done
每调用一次next(g),就计算出数值队列中的下一个元素,当计算到最后一个元素时的下一个元素时,就会抛出异常。
也可以通过`for...in
循环来迭代里面的的数值:
>>> g = fib(6)
>>> for x in g:
... print(x)
...
1
1
2
3
5
8
总结:
在一个生成器中,遇到return
语句或者执行到函数的最后一行,都会中止迭代并抛出异常StopIteration
,如果有return返回值,那么这个返回值就在这个异常的value
中,并不作为生成器函数的返回值。
在我们已知的数据类型中,可以用for
循环遍历的类型有两大类:
一是list
,tuple
,dict
,set
,str
等集合数据类型
二是生成器类型generator
,包括生成器表达式和生成器函数
可以使用isinstance()
判断一个对象是否是Iterator
from collections import Iterator
>>> isinstance((x for x in range(10)),Iterator)
True
>>> isinstance([1,2,3],Iterator)
False
能用next()
调用的对象就是迭代器对象Iterator
,很明显generator
就是迭代器对象:
>>> g = (x for x in range(10))
>>> g
at 0x10203deb8>
>>> next(g)
0
>>> next(g)
1
...
而list
,tuple
,dict
,set
,str
等集合数据类型不能用next()
调用,它们不是Iterator
,而是Iterable
可迭代对象:
>>> list = [1,2,3,4,5]
>>> next(list)
Traceback (most recent call last):
File "", line 1, in
TypeError: 'list' object is not an iterator
当然,我们也可以使用iter()
将Iterable
变成Iterator
:
>>> g = [x for x in range(10)]
>>> g
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> newg = iter(g)
>>> newg
0x10209ffd0>
总结:
能使用for
循环遍历的对象是课迭代对象Iterable
能使用next()
进行取值的对象就是迭代器对象Iterator
list
,tuple
,dict
,set
,str
等集合数据类型不是迭代器对象Iterator
但它们是可迭代对象Iterable
,可以使用iter()
方法将Iterable
变成Iterator
对象