2

我试图了解 python 生成器的一些微妙细节。我编写的一个测试程序,看看我是否可以向/从同一个生成器交替发送和读取值,如下所示:

def injector():
    while True:
        try:
            print 'a'
            v = yield
            print 'b', v
            yield v
            print 'c'
        except GeneratorExit:
            print 'exit'
            break

g = injector()

print 'send none'
g.send(None)
print 'send 2'
g.send(2)
print 'receiving'
v = g.next()
print 'received', v

g.close()

该程序的预期输出是:

send none
a
send 2
b 2
receiving
received 2
c
a
exit

我得到的输出是:

send none
a
send 2
b 2
receiving
c
a
received None
exit

现在,显然,问题是为什么我会得到上述输出?我不了解发电机的工作原理是什么?

4

2 回答 2

3

让我试着澄清一下:

def injector():
    while True:
        try:
            print 'a'
            v = yield
            print 'b', v
            yield v
            print 'c'
        except GeneratorExit:
            print 'exit'
            break

g = injector()

print 'send none'
g.send(None)

这里启动协程。它一直执行到第一个 yield 的结果是从 返回的.send(),然后被丢弃。

协程不打印a任何内容,因此None. 所以丢弃是可以的。

print 'send 2'
g.send(2)

在这里,您将 2 发送到协程,使其从您离开的地方继续。v = 2.

它再次打印2并产生v。你会从g.send()电话中期待这一点。所以在接收和丢弃之后v,你做

print 'receiving'
v = g.next()

在这里,您再次将控制权交给协程,它会打印c,然后a,然后None再次生成,您可以在这里得到。

print 'received', v

因此打印Nonev.

你可能想要的是

g = injector()

print 'send none'
g.send(None)
print 'send 2'
v = g.send(2)
print 'received', v

g.close()

(请注意,最后一个块可以写得更干净漂亮,如下所示:

from contextlib import closing
with closing(injector()) as g:
    print 'send none'
    g.send(None)
    print 'send 2'
    v = g.send(2)
    print 'received', v

)

于 2012-11-29T13:11:01.607 回答
0

因此,您遇到的问题是最后一次通话。首先,它似乎从代码停止的地方开始,打印第'c'一个。然后由于该语句没有产生,它继续在 while 循环中打印'a'。最后,产生输出。none 结果,因为在'a'

于 2012-11-29T13:02:39.473 回答