上文说道列表生成式,这节聊聊生成器
通过列表生成式可以很方便的创建一个了列表,但是受到内存的限制,列表容量肯定是有限的。而且创建一个包含100万元素的列表不仅占用很大的储存空间,如果我们只要访问前面几个元素占用的空间就白白浪费掉了
所以如果说列表的元素可以用一个算法推导出来,那我们不就可以在循环中不断推算出列表的元素,这样就可以不用创建完整的列表,从而节约大量的空间。在python中,一边循环一边计算的机制,称为:生成器(generator)
要创建一个生成器。有很多种方法,第一种方法很简单,只要把列表生成式的[]换成()就可以了。这样就创建一个生成器(generator)
#这一行错误主要是因为生成器必须有一个算式循环出来
那我们怎么才能输出生成器里的值呢,前面说过生成器是要用算法循环出来。我们可以调用next()函数输出
我们每次调用next()函数,计算出生成器L的值,直到最后一个元素,没有下一个元素抛出 StopIteration 错误。
当然上面不断调用next()函数的方法太没有效率了,我们说过生成器是一边循环一边计算。所以上面的例子要使用for循环
所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,而且不用担心StopIteration 错误。
生成器generator非常强大。如果推算的的算法比较复杂,用类似的列表生成式的 for 循环无法实现的时候,还可以用函数来实现
比如,著名的斐波拉契数列(Fibonacci),除了第一个数和第二个数之外,任意一个数都可以由前面两个数相加得到。
1,1,2,3,5,8,13,21,34,55,...
斐波拉契数列用列表生成式写不出来,但是用函数打印出来很容易
赋值语句:a,b = b,a+ b
相当于
t = (b, a + b) # t是一个tuplea = t[0]b = t[1]
上面的函数可以输出斐波拉契数列的前 n 个数
仔细观察,可以看出,fn函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator.
也就是说上面的函数和generator 仅有一步之遥,要想把fn函数变成生成器,只需要把 print(b) 换成 yield(b)就可以了
这样,函数就变成了一个生成器
这就是定义generator的另一种方法,如果一个函数中包含 yield 关键字,那么这个函数就不是普通的函数而是一个生成器generator
既然 fn 函数已经是一个生成器,我们用for循环来调用它
结果跟预想的一样。
但是我们发现了一个问题,在用for循环调用generator时,拿不到函数的返回值即return里的内容,想要拿到返回值必须捕获StopIteration中的值,我们调用next()函数来生成这个错误
领取专属 10元无门槛券
私享最新 技术干货