今天我遇到了yield
的一个有趣的举动,但我并不太了解。这是我的代码:
def a():
def b(x):
print("entering b.")
yield 0
if x == 0:
print("calling b.")
b(x + 1)
print("return from b.")
print("leaving b.")
for x in b(0):
yield x
for x in a():
print(x)
输出:
entering b.
0
calling b.
return from b.
leaving b.
令我感到困惑的是,显式调用b(x + 1)
不会调用b
(!),Python也不会给出任何错误或异常。
现在,显然上面代码中的错误是b(x + 1)
应该真正产生b
产生的值-因此它应该读为:
for x in b(x + 1):
yield x
然后一切正常。
还是,yield
这件事我应该注意吗?
答案 0 :(得分:5)
b(x + 1)
被调用,但是直到在调用函数的上下文中产生时才执行。
使用yield from
产生对b()
的调用所产生的所有值并执行主体:
def a():
def b(x):
print("entering b.")
yield 0
if x == 0:
print("calling b.")
yield from b(x + 1)
print("return from b.")
print("leaving b.")
for x in b(0):
yield x
for x in a():
print(x)
答案 1 :(得分:3)
answer you got so far is right(我已对其进行投票),但我发现您仍在与之抗争,所以让我们尝试以下变体:
def a():
def b(x):
print("entering b.")
yield 0
if x == 0:
print("calling b.")
temp = b(x + 1)
print("calling b resulted in temp =", temp)
print("return from b.")
print("leaving b.")
for x in b(0):
yield x
for x in a():
print(x)
现在让我们在Python 3.x中运行它:
entering b.
0
calling b.
calling b resulted in temp = <generator object a.<locals>.b at 0x800ac9518>
return from b.
leaving b.
也就是说,将temp
设置为调用b(x + 1)
的结果,而 result 就是这个<generator object ...>
东西。
然后您必须对生成器对象进行 的操作,因此这里是第三个变体:
def a():
def b(x):
print("entering b.")
yield 0
if x == 0:
print("calling b.")
temp = b(x + 1)
print("calling b resulted in temp =", temp)
y = next(temp)
print("by doing next(temp), I got", y)
print("return from b.")
print("leaving b.")
for x in b(0):
yield x
for x in a():
print(x)
运行此操作会产生:
entering b.
0
calling b.
calling b resulted in temp = <generator object a.<locals>.b at 0x800ac9518>
entering b.
by doing next(temp), I got 0
return from b.
leaving b.
另一个答案中的yield from
变体基本上意味着“继续调用temp并产生它产生的任何结果,直到它说完成为止”。这个y = next(temp)
仅叫temp。
针对读者的锻炼:尝试以下引用的第四个变体。尝试在运行之前预测会看到什么。你看到你的预言了吗?
def a():
def b(x):
print("entering b.")
yield 0
if x == 0:
print("calling b.")
temp = b(x + 1)
print("calling b resulted in temp =", temp)
y = next(temp)
print("by doing next(temp), I got", y)
try:
print("about to re-enter temp")
y = next(temp)
print("with the second next(temp), I got", y)
except StopIteration:
print("with the second next(temp), I got StopIteration")
print("return from b.")
else:
print("b had x =", x)
print("leaving b.")
for x in b(0):
yield x
for x in a():
print(x)