一文搞懂Python中的yield
发布网友
发布时间:2024-10-08 09:26
我来回答
共1个回答
热心网友
时间:2024-10-08 09:55
yield 关键字在 Python 中有着重要的作用,既可以实现生成器,也可以实现协程。生成器和协程的概念可能对于初学者来说比较抽象,但理解它们的作用和效果是至关重要的。
首先,我们来看看 yield 的英文单词的意思。yield 在英语中的意思是“出产(作物);产生(收益、效益等);提供”。这个词语的含义可以帮助我们更好地理解 yield 在 Python 中的作用。
在初学 Python 的时候,我对于 yield 关键字的认知仅仅停留在它是一种特殊的 return,能够理解其用法即可。自己很少使用,也就没有深入研究过。然而,当我需要处理大量数据,数据的大小甚至超过了电脑的可用内存时,我开始重新审视 yield 的作用。
比如,在操作 db2 数据库查询数据时,当数据结果很大时,我不想一次性将所有数据读入内存,这时我会使用 yield 关键字来返回一行数据,程序处理完后,再取下一行。这种做法可以有效地节省内存空间。
关键字 yield 的用法是,它返回了一个值,但程序并未退出,下一次从 yield 后面的代码继续运行,直到后面没有代码,结束运行。下面我们通过一个简单的例子来看一下其效果:
通过上面的例子,我们可以发现,yield 关键字自动为我们生成了私有方法 __next__,这样就不会将所有数据取出来存入内存中,用多少取多少,可以节省内存空间。
除了节省内存空间外,yield 在数据量较大时,执行速度也会提升。在 Ipython 终端中执行上述代码,我们可以看到使用 yield 的函数执行速度更快。
yield 是自己实现一个生成器最便捷的方式。Python 语言的生成器是最有用的特性之一,但使用不广泛。我曾问过周围使用 Java 的朋友是否有类似的特性,他们回答说没有,网上搜了一下,确实主流的编程语言都没有。因此,Python 的生成器特性没有引起其他语言转 Python 的工程师的关注。
生成器非常有用,尤其是在处理大量数据时。当你需要处理的数据大小超过你电脑的可用内存时,生成器的懒加载(用的时候才读入内存)就非常有效。
比如,在读取文件时,如果你一次性读取很大的文件,可能会让内存一下子就满了。推荐的做法是使用文件本身的生成器,这样读多大的文件,也不会撑爆内存。
想深入学习生成器、迭代器、可迭代对象,可以看我以前的推文:《python 基础系列--可迭代对象、迭代器与生成器》、《深入理解迭代器和生成器》。
yield 关键字还可以实现协程。虽然现在有 asyncio 和 await 关键字来方便地实现协程,但在之前,实现协程就靠的是 yield。
yield 有一个 send 方法,可以改变 yield 的返回值。下面是一个示例代码:
第一次执行 x 的 next 方法时,函数执行到第一个 yield 处,打印了 a 返回了值 1,此时变量 a 并未获取到 yield 的返回值,a 为 None。当执行 x.send(4) 时,a 才获取到值 4,程序运行到第二个 yield 处,后续过程也是一样。
利用这一特性,我们可以和被调用的函数通信,进而可以实现一个生产者消费者模型。下面是示例代码和运行结果:
运行结果如下:
produce 和 consume 函数在一个线程内执行,通过调用 send 方法和 yield 互相切换,实现协程的功能。
关于协程的学习,可以看我以前的推文:《协程学习笔记》、《并发时用多线程还是协程?》。