在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。在了解生成器之前需要了解什么是可迭代对象(iterables,可迭代序列):
什么是可迭代对象呢?
最简单的定义就是:可以使用for...in...语句进行循环的对象,比如字符串、列表、元组、字典以及迭代器、生成器都是可迭代对象。
迭代
你可以创建一个列表,然后逐一遍历,这就是迭代
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
mylist是可迭代的对象,当你使用列表解析时,你创建一个列表,即一个可迭代对象
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
总结:
1.迭代器一定是迭代对象,迭代对象不一定是迭代器
2.生成器一定是迭代器,迭代器不一定是生成器
3.使用for...in...来遍历迭代对象是最常用的方式
生成器(generator)
生成器是一种特殊的迭代器。只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。
Ps.生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常
生成器是迭代器,但你只能遍历它一次(iterate over them once)
因为生成器并没有将所有值放入内存中,而是实时地生成这些值
注意,你不能对一个生成器遍历两次(阅后即焚),每个生成器只能被使用一次
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
这和使用列表解析地唯一区别在于使用()替代了原来的[]
Ps.不能执行for i in mygenerator第二次,因为每个生成器只能被使用一次: 计算0,并不保留结果和状态,接着计算1,然后计算4,逐一生成
yield
1. yield 是一个类似return 的关键字(不同之处,yield返回的是一个生成器:),迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行。
(简单的解释:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始)
带有yield的函数不只用于for循环,可用于某个函数的参数,只要这个函数的参数允许迭代参数。比如array.extend函数,它的原型是array.extend(iterable)
>>>def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator =createGenerator() # create a generator
>>> print(mygenerator) #mygenerator is an object!
>>> for i in mygenerator:
... print(i)
0
1
4
这例子说明当你知道函数将产生大量数据只能被读取一次数据时,使用生成器是十分有效的方法
yield
当你调用这个函数时,函数中编写的的代码没有执行。这个函数只是返回一个生成器对象
当每次调用for循环使用生成器时,都会执行代码:
第一次函数运行会从头开始,直到yield,然后将返回循环的首个值,每次调用,都会执行函数中的循环一次,返回下一个值,直到没有值可以返回
当循环结束,或者不满足”if/else”条件,导致函数运行但不命中yield关键字,此时生成器被认为是空的