协程本质上是一类?

时间:2018-11-03 12:19:25

标签: python generator coroutine

我正在按照指令学习协程

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应该有她的原因。

1 个答案:

答案 0 :(得分:3)

  

似乎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