生成器(generator)是一种可迭代对象。
在处理包含大量数据时,如果使用list来进行操作,会导致内存占用大,效率低。生成器通过延迟计算,实现了一种边循环边计算的可能,只有在需要的时候才返回相应的结果,而不是一次性返回一整个结果列表,因此可以有效地节省了大量的空间。
首先,根据列表生成式,将[]改成()即可创建一个generator
>>> a = (x * x for x in [1,2,3]) # 列表生成式:a = [x * x for x in [1,2,3]]
# 如果你想转成list类型,可以直接用list(a)。
输出元素,可以使用next()
>>> next(a)
1
>>> next(a)
4
>>> next(a)
9
每一次调用next(a),a就会接着上一次的循环输出下一次的结果。当循环完全部元素后,再调用next(a),就会报错。
另外,因为生成器本身是可迭代对象,所以你也可以使用for in 循环遍历直接输出结果。
>>> for x in a:
print(x)
1
4
9
对生成器有了初步认识后,我们就可以开始掌握关键字yield了。
其实很简单,关键字yield的作用就是替代关键字return,如果一个函数中使用了yield来返回结果,我们就认为这个函数是一个生成器。
def func(n):
for i in range(1,n):
result = i * i
yield result
# 将(x * x for x in [1,2,3])用函数的方式表示
了解生成器(generator)与关键字yield的知识后
我们将上面的代码扩展一下
def func(n):
for i in range(1,n):
result = i * i
yield result
func = func(5)
for x in func:
print(x)
for x in func:
print(x)
运行结果:
>>>
1
4
9
16
结果可知,本应该输出了两次循环的结果,却只输出了一次循环。如果你在两个循环中间,添加一个print(list(func))语句,你就会发现由generator转换成list的func是空的,即func=[],func内部的元素似乎被“清空”了。
注意:一个生成器只能遍历一次。
为什么会这样呢?其实在调用next()方法的时候就大概明白了,每一次调用next()的时候,循环处于“工作”状态,不调用的时候,程序就处于一种“暂停”的状态,直到再次被调用,才会“工作”。当循环到最后一个元素后,我们再调用next()时就会报错。这说明了生成器只是代表了一次完整的循环中不断计算结果的过程。
那如果你还是希望能让你的生成器能被多次调用的话,你可以这样做
1、将生成器转换成list,再进行遍历
func = list(func(5))
2、需要遍历几次,就生成多少个可迭代对象(generator),再分别遍历
func1 = list(func(5))
func2 = list(func(5))