首页 > 解决方案 > 协程本质上是一个类?

问题描述

我正在按照说明学习协程

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实际上是 a class grep,因为它首先启动了一个生成器对象。

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

标签: pythongeneratorcoroutine

解决方案


似乎 yield 表达式作为functools.partial, [除了] 它应该使用next().

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

协程很难遵循,我对正确方向的理解是继续没有进一步的副作用,因为 Python 命名它def而不是class

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

您可以想到任何表达式的一种方法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

推荐阅读