要理解yield的作用,就必须理解生成器是什么。在理解生成器之前,必须先理解迭代器。
Iterable 迭代器
当创建一个列表时,可以逐个读取它的项。逐项读取其项称为迭代:
Mylist就是一个可迭代的对象,这就是迭代
所有可以用for … in … 的对象都是可迭代的对象,即迭代器,比如list,string
这些迭代器非常方便,因为你可以随心所欲地读取它们,但是这会将所有的值都存储在内存中,当有很多值时,这可能就不是你想要的效果了,这个时候就需要生成器登场了
Generators 生成器
生成器是迭代器,这种迭代器只能迭代一次。生成器不会将所有值都存储在内存中,它们会动态生成这些值:
在python3中(x*x for x in range(3)) 返回的并不是一个元祖,而是一个生成器,当用for迭代时才会逐个得到元素。用[]就会返回一个list而不是生成器,这里用个()得到一个生成器,那么如果有更复杂的逻辑呢,该如何得到一个生成器呢,这个时候就需要yield登场了
Yield 关键字
yield是一个与return类似的关键字,只是函数将返回一个生成器。
这是一个简单的例子,但是当你知道函数将返回一组只需要读取一次的值时,这是很方便的。
要掌握yield,你必须了解,在调用函数时,在函数体中编写的代码不会运行。函数只返回生成器对象
然后,你的代码将从每次使用生成器时停止的地方继续。
接下来是最难的部分:
for函数第一次调用在函数中创建的生成器对象时,它将从头运行函数中的代码,直到达到yield,然后返回循环的第一个值。然后,每个剩下的调用将再次运行你在函数中编写的循环,并返回下一个值,直到没有要返回的值为止。
一旦函数运行结束,生成器就会被认为是空的,就不会再命中yield。这是因为循环已经结束。
这就是yield的用法,简单的说就是用yield来创建生成器,此外python自带了一个创建生成器的工具Itertools
Itertools
itertools模块包含一些特殊的函数来操作迭代器。有没有想过复制一个生成器?用一行代码将嵌套列表中的值分组?如何使用map和zip时不再创建list?这时Itertools就是你最好的选择, 简单举个例子,如何得到一个序列的排列组合,以下例子就是返回一个排列组合的生成器。
本质上来说,迭代器能迭代是因为实现了两个方法:__iter__()方法__next__()方法
思考一下:如何处理一个10G的文件,统计出单词数量?