为什么这个协程会永远生成None值?

时间:2014-07-21 01:08:50

标签: python yield coroutine

我有一个简单的协程

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

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

来填充它
gen = id()
next(gen)

for x in gen:
    print(x)

这将永久打印None。我的直觉是id的生成器只有yield一个值sent一个值,但在这种情况下,它自己生成None个值。

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

3 个答案:

答案 0 :(得分:3)

正如其他人所指出的那样,调用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完全相同的方法,只会传递{{1}对象。请考虑您的NULL循环基本上相当于这样做:

for x in gen

你知道问题是什么。

认识到协同程序和生成器实际上是完全独立的概念很重要,即使它们都是使用iterable = iter(gen): while True: try: x = next(iterable) except StopIteration: break print(x) 关键字实现的。一般来说,你不应该在协程上进行迭代,而且一般来说,你不需要/想要yield事物进入生成器。我强烈推荐David Beazley的PyCon coroutine tutorial以获取更多关于此和协程的更多信息。

答案 1 :(得分:2)

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

  

generator.next()

     

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

答案 2 :(得分:0)

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
...