python生成器中产生的确切返回点

时间:2015-06-24 23:32:16

标签: python generator

为了教自己Python生成器,特别是他们的send()方法,我想写一个玩具示例,它允许我计算一个“可中断的”Fibonacci序列。

最终我成功了,但我不明白到底发生了什么。考虑这两个例子。

成功的例子:

def genFib(a=0, b=1):
    while True:
        c = yield a+b
        if c:
            a, b = b, c
        else:
            a, b = b, a+b
    return
​
fib_number = genFib()
​
print fib_number.next()
print fib_number.next()
print fib_number.next()
print fib_number.next()
print fib_number.next()
print fib_number.send(100)
print fib_number.next()
print fib_number.next()
​
1
2
3
5
8
105
205
310

我认为失败会起作用:

def genFib(a=0, b=1):
    while True:
        c = yield a+b
        a, b = b, c
    return
​
fib_number = genFib()
​
print fib_number.next()
print fib_number.next()
1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-59-4513153ea517> in <module>()
      8 
      9 print fib_number.next()
---> 10 print fib_number.next()

<ipython-input-59-4513153ea517> in genFib(a, b)
      1 def genFib(a=0, b=1):
      2     while True:
----> 3         c = yield a+b
      4         a, b = b, c
      5     return

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

为什么第二个示例不起作用?特别是,第二个示例似乎在所有中为None分配了值c,但第一个执行发电机。为什么?第一次c被调用时,如何分配给next(),而不是下一个next()时间?

我的理解是生成器从之后的行开始恢复执行(当它们被再次调用时),但是我的例子让我认为这是错误的,至少在某些情况下是这样。执行从哪里恢复?它是否会重新执行yield行,但这一次以某种方式在yield之后遗漏了所有内容? c如何分配到None

1 个答案:

答案 0 :(得分:2)

yield有点奇怪的表达。在评估右侧之后,yield执行暂停,但在分配之前暂停执行。

yield语句中返回的值是.send到生成器的值。由于您正在调用.next而不是.send,因此从yield表达式(c)返回的值为None。在第一个示例中,检查c的真实性是正常的,如果它是假的则不会被使用(例如None)。但是,在第二个示例中,c未经过检查,因此您最终会将None添加到整数(这显然不会产生理想的结果)。