生成器协程与原生协程的区别

11

我刚刚阅读了PEP0492,其中谈到了协程的新方法,但该PEP未能让我理解生成器协程和本地协程之间的区别。有人可以告诉我区别吗(最好附带示例)?

据我所知,它们使用不同的单词(yield/yield from 和 await/async/yield)。我知道本地协程在结束时需要一个yield,但是对于基于生成器的协程也是如此。


1
区别在于语法;它是一种语法糖,使其更清晰、更简洁。 - Martijn Pieters
所以,除了语法之外,它们是完全相同的吗?听起来太奇怪了... 这在 PEP 中不会被批准。 - Koldar
1
装饰器也是语法糖,你可以在函数声明之后使用 func = decorator(func)。上下文管理器是 try:...except:...finally: 的语法糖。Python 一直强调可读性和目的的清晰度,这与这些目标完全契合。 - Martijn Pieters
用那种方式表达,似乎更加合理。给出一个答案,我会接受它。 - Koldar
3个回答

11
为了更好地阐述Mike S所写的内容:在CPython中,本地协程与生成器共享大部分代码,因此功能上几乎没有区别。但是,我认为PEP-492超出了仅仅“语法糖”的门槛。生成器和本地协程具有不同的目的,因此新语法可以澄清作者的意图,并且可以做出旧语法无法完成的操作。以下是一些示例:
  • 生成器是可迭代的,本地协程则不是。
  • 本地协程还允许新的语法,如异步上下文管理器和异步迭代器。
  • 协程具有有用的调试信息,例如,如果您从未await协程对象,则会发出警告。

新语法还很好地反映了asyncio库,并类似于其他语言使用的关键字。


1
[https://docs.python.org/3/reference/expressions.html#yield-expressions]是一个表达式,而且一直都是。`await`不能在任何`yield from无法使用的地方使用。事实上,区别正好相反:yield from可以在await无法使用的地方使用,即非async`函数(这种限制有时有助于捕获错误)。 - abarnert
感谢@abarnert。你绝对是正确的。我已经从我的答案中删除了那个错误的陈述。 - Mark E. Haase
@MarkE.Haase,我说本地协程在幕后是基于生成器的,这样说对吗? - EngineerSpock
@EngineerSpock 是的 - Mark E. Haase

4
没有功能上的区别。使用关键词 asyncawait 的“本地协程”只是语法糖,以前实现过的“基于生成器的协程”。如果不需要支持旧版 Python,则建议在 3.5 文档 中使用 asyncawait 关键字。

0

传统上编写协程的方式涉及回调。尽管回调可能最初很方便,但在我看来,它们会导致高度复杂和复杂的代码,这至少不能算是Pythonic。此外,yield(特别是自Python 3.3以来的yield from)使实现协程变得更加容易和Pythonic。

使用生成器,您可以轻松地将代码分成初始部分和回调部分。

@asyncio.coroutine
def print_sum(x, y):
    result = yield from compute(x, y)

    #write callback code
    print("%s + %s = %s" % (x, y, result))

好的,但这并没有回答问题“原生协程和基于生成器的协程有何不同?” - Koldar
它们不是...只是实现同一件事情的不同方式。 - hspandher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接