Python 2.2 引入了 yield 关键字实现的生成器函数,大约五年后,Python 2.5 实现了“PEP 342 — Coroutines via Enhanced Generators”(https://www.python.org/dev/peps/pep-0342/)。这个提案为生成器对象添加了额外的方法和功能,其中最值得关注的是 .send() 方法。
与 .__next__() 方法一样,.send() 方法致使生成器前进到下一个 yield 语句。不过,.send() 方法还允许使用生成器的客户把数据发给自己,即不管传给 .send() 方法什么参数,那个参数都会成为生成器函数定义体中对应的 yield 表达式的值。也就是说,.send() 方法允许在客户代码和生成器之间双向交换数据。而 .__next__() 方法只允许客户从生成器中获取数据。
这是一项重要的“改进”,甚至改变了生成器的本性:像这样使用的话,生成器就变身为协程。在 PyCon US 2009 期间举办的一场著名的课程中(http://www.dabeaz.com/coroutines/),David Beazley(可能是 Python 社区中在协程方面最多产的作者和演讲者)提醒道:
生成器用于生成供迭代的数据
协程是数据的消费者
为了避免脑袋炸裂,不能把这两个概念混为一谈
协程与迭代无关
注意,虽然在协程中会使用
yield产出值,但这与迭代无关 16——David Beazley
“A Curious Course on Coroutines and Concurrency”
16摘自“A Curious Course on Coroutines and Concurrency”(http://www.dabeaz.com/coroutines/Coroutines.pdf)的第 33 张幻灯片,题为“Keeping It Straight”。
我会遵从他的建议,至此结束本章(因为本章真正讨论的是迭代技术),而不涉及把生成器当成协程使用的 send 方法和其他特性。第 16 章会讨论协程。