【问题标题】:Why does this coroutine generate None values forever?为什么这个协程永远生成 None 值?
【发布时间】:2014-09-11 10:45:08
【问题描述】:

我有一个简单的协程

def id():
    while True:
        x = yield
        yield x

我可以用它来创建一个生成器,并用next启动它

gen = id()
next(gen)

for x in gen:
    print(x)

这将永远打印None。我的直觉是,id 的生成器只会在 sent 对它产生一个值后才生成 yield 值,但在这种情况下,它会自行生成 None 值。

有人可以向我解释这种行为吗? x = yield 语句是否默认 xNone

【问题讨论】:

    标签: python yield coroutine


    【解决方案1】:

    正如其他人指出的那样,调用next(gen) 等同于调用gen.send(None)。如果您查看C code for generator objects,您可以看到这一点:

    PyDoc_STRVAR(send_doc,
    "send(arg) -> send 'arg' into generator,\n\
    return next yielded value or raise StopIteration.");
    
    PyObject *
    _PyGen_Send(PyGenObject *gen, PyObject *arg)
    {
        return gen_send_ex(gen, arg, 0); 
    }
    ...
    static PyObject *
    gen_iternext(PyGenObject *gen)
    {
        return gen_send_ex(gen, NULL, 0); 
    }
    

    如您所见,iternext(当您调用next(generator_object) 时会调用它)调用与generator_object.send 完全相同的方法,只是它始终传入NULL 对象。考虑到您的 for x in gen 循环基本上相当于这样做:

    iterable = iter(gen):
    while True:
        try:
            x = next(iterable)
        except StopIteration:
            break
        print(x)
    

    你会看到问题所在。

    意识到协程和生成器实际上是完全独立的概念很重要,即使它们都是使用yield 关键字实现的。通常,您不应该迭代协程,并且通常您不需要/不想将 send 东西放入生成器中。我强烈推荐 David Beazley 的 PyCon coroutine tutorial 了解更多关于这个和一般协程的信息。

    【讨论】:

      【解决方案2】:

      for 语句调用生成器的next 方法而不是send 方法。根据文档(Python 2.7),这导致yield 语句返回无:

      generator.next()

      开始执行生成器函数或 在最后执行的yield 表达式处恢复它。当一个发电机 使用next() 方法恢复函数,当前yield 表达式 总是评估为None

      【讨论】:

        【解决方案3】:

        yield 是一个仅在函数内部有效的表达式。 yield 表达式的值为 None。所以你的函数产生None,然后将yield(None)的结果分配给x,然后产生x。为了更好地展示正在发生的事情,让我们从第一个收益中产生一些东西,看看会发生什么。

        def id():
            while True:
                x = yield 5
                yield x
        

        现在将生成以下序列:

        5
        None
        5
        None
        5
        None
        5
        None
        ...
        

        【讨论】:

          猜你喜欢
          • 2021-03-20
          • 2017-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多