【问题标题】:Coroutine is a class in its nature?协程本质上是一个类?
【发布时间】:2019-04-07 10:41:21
【问题描述】:

我正在按照说明学习协程

def grep(pattern):
    print("Looking for %s" % pattern)  # prime it(explain shortly)
    while True:
        line = (yield) # expression
        if pattern in line:
            print(line)

测试一下

>>> g = grep("python")
>>> g.next()
Looking for python
>>> g.send("coroutine test")
>>> g.send("learning python")

看起来yield表达式作为functools.partial执行,不包括它应该使用next()启动

此时,def grep 实际上是一个class grep,因为它首先启动了一个生成器对象。

协程很难遵循,我对正确方向的理解是继续没有进一步的副作用,因为 python 将其命名为 def 而不是 class 应该有她的理由。

【问题讨论】:

  • type(grep)functiontype(grep('foo'))generator。我不确定您看到的与functools.partial 有何相似之处。
  • 我猜在它的实现细节中它是一个类。但是被命名为考虑语法的函数。 @timgeb
  • @Sawajin 你不是在问实施细节吗? grepfunction 的一个实例,grep('foo')generator 的一个实例。如果它们是类,它们将是 type(或某些元类)的实例。
  • 对于其他读者:这个问题似乎源于 David Beazley 的 A Curious Course on Coroutines and Concurrency(见幻灯片)

标签: python generator coroutine


【解决方案1】:

看起来,yield 表达式作为functools.partial 执行,[除了] 它应该使用next() 启动。

我不确定是什么让你这么说,但我没有立即看到相似之处。 functools.parital 旨在将一些 args/kwargs 部分绑定到可调用对象,并让您保存一些其他 args/kwargs 以供用户调用。 (“partial() 用于部分函数应用程序,它‘冻结’函数参数和/或关键字的某些部分,从而产生一个具有简化签名的新对象。”)这并不是这个生成器的实际情况,或者任何生成器。

协程很难遵循,我是否理解正确的方向,因为 Python 将其命名为 def 而不是 class,所以没有进一步的副作用?

他们很棘手,同意你的观点。但我不确定我是否看到协程“本质上就像一个类”。协程是一个专门的生成器。生成器是用def 定义的,并且能够暂停和恢复它们的执行。这描述的是生成器,而不是类,对于初学者来说,仅将 def 替换为 class 在语法上是无效的。

您可以想到像a = yield b 这样的任何表达式的一种方法是标记一个断点。

当您调用next(g) 时,它会前进直到遇到yield 语句,然后停在那里。它将结果值推送到调用堆栈它将暂停执行并停在那里,当您再次调用 next() 时可以恢复。 (这是函数和生成器之间的关键区别,以及函数和协程之间的扩展。)

第一次调用next()lineNone。 (基本上,line = yield None。)您将无法对此进行迭代,因为您不能说for pattern in None。在这种情况下,“启动”的含义可能是指对next(g) 的初始调用类似于g.send(None)

现在,当您将其他值发送到生成器时,它们将被分配给 line,而 pattern 仍然是“python”。如果在.send() 中找到“python”,它就会被打印出来。

>>> g = grep("python")
>>> n = g.send(None)  # equiv to next(g); stop at line = (yield)
Looking for python
>>> n is None
True
>>> g.send("coroutine test")
>>> g.send("coroutine test")
>>> g.send("coroutine test")  # no match
>>> g.send("learning python") # match
learning python
>>> g.send("python3.7") # match
python3.7

【讨论】:

  • “在这种情况下,“启动”的含义可能是指对 next(g) 的初始调用类似于 g.send(None)。”,这种见解让我大开眼界。谢谢。
  • 我认为它类似于部分,因为如果 grep 被定义为标准函数。
  • 好的,我有点明白你在说什么 - 但它并不真正需要“冻结”,因为 grep() 实际上只调用一次。之后,它完全停留在while True 循环中,pattern 保持不变。以这种方式定义的任何函数都是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2012-06-07
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
相关资源
最近更新 更多