Python生成器——懒到欠揍,但很经济

生成器的特点是工作到一半,就会停下来看别人干活直至有人踢它屁股,这时它才继续往下干活。实现这一功能的精髓要用到yield。

生成器是一种特殊的迭代器,因此我们先来了解一下什么是迭代器。我们都知道著名的斐波那契数列:1、1、2、3、5、8、13、21、34……从第三个数开始,每个数都可以由其前面的两个数相加得到,这就是一个迭代过程。很显然,这是一个不收敛的数列,我们无法用列表或者使集合去一次性将它们提取出来。这时候,如果我们把这样一个迭代过程封装成一个迭代器,只有在调用一次它的时候它才进行一次迭代,并且只保留当前的迭代结果,这样一来,程序的运行速度能得到提高,同时也不会对内存造成严重的负担。迭代器可以表示一个无限大的数据流,也可以表示一个有限的数据流。

从代码的角度讲,所有可以被next()函数调用并不断返回下一个值的对象就叫做迭代器:Iterator。与迭代器相近的一个概念是可迭代对象(Iterable),凡是可用for循环遍历的对象都是可迭代对象,比如list、dict和str等。但是这几个对象不是迭代器,这一点在上一段已经从迭代器的特点说明,不再赘述。然而,世事无绝对,通过iter()函数,可以将它们变成迭代器。

由此,我们可以建立这样一个斐波那契数列生成器:

def generate():
    b,c = 0,1
    while True:  
        b,c = c,b +c  #迭代公式
        yield c
    return "fault"  #出错时的返回值

y = generate()   #产生一个生成器对象,但不调用生成器
for i in range(15):  #调用15次
    print(y.__next__(),end="  ")  #使用next()方法调用生成器

yield的作用是让生成器在这里暂停执行,执行下一条程序指令。当下一次调用next()函数时,生成器从暂停的地方继续往下执行。一次,每调用一次产生一个值,调用15次产生15个值,如下图所示:

《Python生成器——懒到欠揍,但很经济》 斐波那契数列

这种类型的生成器并不需要参数,当我们需要给生成器内部传递参数时,我们需要用到send()函数,因为next()函数不具备该功能。看下面这样一段代码:

def sing(word1):
    print(word1)
    while True:
        word2 = yield  #每次调用时生成器都停留在这里
        print(word2)


a = sing("如今走过这世间")
a.send(None)  #可以替换成a.__next__()
a.send("万般流连")

上述代码,如果不用while循环,则没办法使每次调用的结果程序都停留在yield这里,而是执行完print(word2)变结束了,这使程序会报错。在第一次使用需要传递参数的生成器时,我们不能直接使用send()函数传递我们想传递的参数,因为此时函数停在yeild,并不需要到这个参数。因此我们可以用next()函数来进行第一次调用,然后再调用send()传递参数并调用。当然,如果我们非要用send()函数实现第一次调用时,应该传递一个空参数。运行结果如下所示:

《Python生成器——懒到欠揍,但很经济》 运行效果

至此,大功告成!

    原文作者:再忙一点儿
    原文地址: https://www.jianshu.com/p/27fe9cd9275c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞