为了教自己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
?
答案 0 :(得分:2)
yield
有点奇怪的表达。在评估右侧之后,yield
执行暂停,但在分配之前暂停执行。
yield
语句中返回的值是.send
到生成器的值。由于您正在调用.next
而不是.send
,因此从yield表达式(c
)返回的值为None
。在第一个示例中,检查c
的真实性是正常的,如果它是假的则不会被使用(例如None
)。但是,在第二个示例中,c
未经过检查,因此您最终会将None
添加到整数(这显然不会产生理想的结果)。