我有一个简单的协程
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
语句是否默认x
为None
?
答案 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
...