本节主要想让大家搞得下面几个问题:
1.什么是生成器?2.为什么要使用生成器?3.生成器与迭代器有什么关系?4.如何自定义一个生成器?
如果你已经通过上一节内容比较深入的理解了python中的迭代器,那么你就可以比较轻松的理解本节要讨论的生成器。
在python中生成器的定义很简单,就是带有yield关键字的函数。
为了理解,首先我们定义一个普通的函数,该函数的功能就是返回多个自然数加一后的值,代码如下:
非法简单,定义出一个list,用于存储多个自然数加一后的值,然后将这个list通过return关键字返回,再通过for进行迭代输出。
接着来定义一个生成器,该生成器的功能依旧是返回多个自然数加一后的值,代码如下:
观察这一小段代码,可以发现在generator()方法中使用了yield关键字而不是常见的return关键字,yield关键字的作用就是返回yield关键字后面表达式的值,同时将程序中断并保存程序运行到这一步的上下文,这一句可能有点绕,拆分来看,yield在这段代码中的作用就是:
1.返回yield关键字后面表达式的值,这里就是返回i+1的值
2.中断程序,要程序运行停止在这一步
3.保存程序运行到这一步的上下文,在程序恢复运行时使用此前保存好的上下文
到这里我相信你已经能理解,带有yield关键字的函数就是生成器的含义,还有点要注意,生成器中不允许有return关键字
上面两端代码输出的结果是一致的,但是使用的东西却完全不同,可以使用python内置的type()函数来看看nogenerator()和generator()这两个函数返回的对象的类型。
结果如下:
普通函数nogenerator返回的是一个list类型对象,而生成器函数返回的是一个generator(生成器)
那为什么要使用生成器呢?普通函数就可以满足我们的需求了。
使用生成器当然有好处,最明显的就是它很省内存,使用生成器可以轻松的将十几G的文件读入到程序中进行处理。之所以这么省内存,yield功不可没。
其实生成器与迭代器有很多相似之处,比如都可以使用next()方法获取下一个值,都可以被for迭代,都只能使用一次,同样通过上面定义的generator()方法来做演示,代码如下:
代码运行结果如下:
其实,生成器就是迭代器另一种更加优雅的实现方式,生成器利用了yield关键字实现了迭代器的所有功能,同时让代码变得更加的简明,符合python主义(在保持可读性的同时使用尽量短的代码实现自己的需求)
需要注意的是,yield关键字后面表达式对应的值不会在函数被调用时就立刻返回,而是当next()方法被调用时才会返回,而通过for进行迭代其本质也是调用next()方法
还记得在迭代器那一节中我们是如何实现一个计算斐波那契数列的迭代器的吗?现在学了生成器后觉得那段代码又臭又长,这里我们通过生成器从新实现一下,代码如下:
输出了如下结果:
生成器表达式
在python中除了通过定义拥有yield关键字的函数来获得生成器外,还可以通过生成器表达式的形式来得到一个生成器
比如将下面这个生成器改写成生成器表达式的形式
改写
它跟列表生成式的写法非常相近,将小括号换成中括号就成列表生成式了
通过生成器表达式生成的生成器同样只能使用一次,而使用列表生成式生成的列表依旧可以使用多次
结尾
本章对python中生成器的讨论就到这里,其中对yield关键字更多高级点的用法会抽出单独的一节来讨论,如果文章中有错误,请指出。
领取专属 10元无门槛券
私享最新 技术干货