分享

一文搞懂python生成器

 xiaoyimin 2019-08-16

要说生成器,就不得不先说一下列表推导式。列表推导式为我们提供了一个快速生成列表的方式。

列表推导式示例:

num_list=[i**2 for i in range(1,6)]

上述代码会生成由1-5这个5个数字的平方组成的列表。

但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

创建num_list和gen的区别仅在于最外层的[]和(),num_list是一个列表(list),而g是一个生成器(generator)。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过generator的next()方法:

generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next()方法比较变态,正确的方法是使用for循环,因为generator也是可迭代对象

定义generator的另一种方法是使用yield关键字。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个生成器。生成器函数与其他普通函数有很多不同,该函数返回的是一个对象,而不是像其他函数return一个或几个值那样。如果想要得到该函数的返回值,需要调用next()函数。

上图中的odd函数,由于使用了关键字yield,于是成为了生成器。当通过odd()调用它时,返回的是一个生成器对象,并赋值给num变量。

如果要真正执行函数体内的内容,需要调用next函数,如下图所示:

生成器函数在执行过程中,遇到yield就中断,下次又继续从yield下一行代码执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就会报错。

生成器是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。赶快自己动手试一下吧!

著作权归作者所有

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多