之前在别人的一些code和python爬虫的学习中经常遇到这个关键字,一开始以为和循环没有什么区别,后来粗略地看了一下说明,结果越看越迷糊,加之发现了自己存在的知识漏洞,因此不得不好好学习一下相关概念
要理解yield,就必须先理解迭代(iteration)的相关概念.下边是一段摘自百度百科的定义:
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值
有两点需要注意:
①逼近所需目标或结果,例如我们已经创建并初始化了一个列表(list)对象L,现在想在L中查找某个元素的值或者位置等,最简单的可以利用迭代从头对到尾对列表中的每个元素进行搜索,直到找到目标为止。
②迭代得到的结果会作为下一次迭代的初始值:例如按照笛卡尔积的定义和运算法则,现在对于若干个集合A,B,C,D。。。(按照定义,它们为要么空集,要么为由有序关系对所组成)之间进行笛卡尔积的运算,即AxBxCxDx。。。,即要按照先后顺序和每一步所取得的结果去循环--先计算AxB,得到一个结果result1(也是一个集合),再让result1去xC,又得到了新的结果result2,再让result2去xC,以此类推。
另外一个例子就是设定一个变量并初始化,利用for循环让其不断自增,最后得到对应的结果。
看懂了迭代后,再来理解yield就不难了,实际上它就是生成器(generator)在python语言中的表述。
关于生成器(generator)的概念(摘自wiki):
In computer science, a generator is a special routine that can be used to control the iteration behaviour of a loop. In fact, all generators areiterators.[1] A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function butbehaves like an iterator.
可以看出,与一般迭代相比,generator可以用于控制迭代的行为,同时也能返回对象。但与array能同时包含所有的value不同,generator一次只能包括一个,因此对内存的要求很低.另外与我们一开始接触它时的直观感受相同,generator看起来确实像一个函数,不过表现形式则是iterator。
以下代码实例转自廖雪峰的官网:
生成斐波那契数列
1.
简单也是传统的写法,利用while循环:
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b #python2标准的写法
a, b = b, a + b #不用像c那样设置tmp变量,一步到位~
n = n + 1
这里的话执行fab(5):
>>> fab(5)
1
1
2
3
5
与文章中评论的那样,代码的复用性较差,即无法保存中间生成的值。
2.利用列表来保存:
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
可以通过for循环来获得返回值(列表)里边的元素
3.通过iterable对象来迭代
for i in range(1000): pass
会导致生成一个 1000 个元素的 List,而代码:
for i in xrange(1000): pass
则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。
4.利用class,跳过。
5.使用yield
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
调用及输出:
>>> for n in fab(5):
... print n
...
1
1
2
3
5
看起来与2中的列表方法类似,但此例中的fab(5)则是一个生成器,调用fab(5)则会首先返回一个iterable对象,而不是去执行函数。之后在循环过程中每次都会执行fab函数内部的代码,到了yield b时,生成器处于暂停状态,fab函数返回一个迭代值。下次迭代时,代码从yield b的下一条语句继续执行,即完成对a,b的更新和n的自增,直到再次遇到yield。
也可以手动调用next方法(在python3中调用像f.next()的方法会shell提示attribute error,因为在新版本中该方法应该为next(f)),也可以逐一获得结果,最后会抛出StopIteration的异常,表示迭代完成。
参考资料:
1.https://baike.baidu.com/item/迭代/8415523?fr=aladdin
2.https://en.wikipedia.org/wiki/Generator_(computer_programming)
3.https://www.liaoxuefeng.com/article/001373892916170b88313a39f294309970ad53fc6851243000