生成器
学习资料来自廖雪峰老师。
能在循环的过程中,不断推算出后面的元素,以此减少存储空间。
generator功能很强大,多练练。
创建generator的方法有多种。
第一种,将列表生成式的[]
改成()
举个例子:
>>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10)) >>> g <generator object at 0x10941bc78>
那么怎么输出生成器中的元素呢?
-
可以用
next()
函数,获取generator的下一个返回值。但是每次只能返回一个值,如果元素多的话,这就贼麻烦了。 -
所以我们可以换种方式。generator其实也是可迭代对象,那就能用
for
循环输出啦。
举个例子:
>>> for n in g: print(n)
1 4 9 16 25 36 49 64 81
生成generator的第二种方法:函数
当推算的算法比较复杂,不能用类似列表生成式的for循环实现时,就可以用函数来实现。
举个例子:斐波拉契数列。
//先用函数打印出来,看看是什么样的
>>> def fib(max): n,a,b=0,0,1 while n<max: print(b) a,b=b,a+b n = n+1 return 'done'
>>> fib(6) 1 1 2 3 5 8 'done'
(这里有个赋值语句需要注意:
a,b = b, a+b
相当于:
t = (b , a+b) #t是一个tuple
a = t[0]
b = t[1]
忽略临时变量t,直接赋值。)
那么怎么把函数变成generatoer呢?
很简单,指需要把print(b)
改成yield b
就可以了。
来看下运行效果:
>>> def fib(max): n,a,b =0,0,1 while n < max: yield b a,b = b,a+b n = n+1 return 'done'
>>> for i in fib(8): print(i)
1 1 2 3 5 8 13 21
generator和函数的执行流程不一样。
函数是顺序执行,遇到return
或者最后一条语句就返回。
generator是在每次调用next()
的时候执行,遇到yield
语句返回。再次执行时从上次返回的yield
语句处继续执行。
上面说过因为next()实在麻烦,所以一般都是用for循环来迭代输出generator的值。
但是观察上面的例子会发现,for循环拿不到generator的return
语句返回值(因为是遇到yield就返回的)
如果想要捉到generator的return返回值,就要捕获一个StopIteration
错误,返回值包含在StopIteration
的value
值中:
>>> g = fib(8) >>> while True: try: x = next(g) print('g:',x) except StopIteration as e: print('Genrator return value:',e.value) break
g: 1 g: 1 g: 2 g: 3 g: 5 g: 8 g: 13 g: 21 Genrator return value: done
while true
是一个无限循环,相当于C语言中的while(1)
.