我今天遇到了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
的东西?
调用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)
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)
的结果,结果就是这个<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
变体基本上意味着“继续调用温度并屈服于它产生的任何东西,直到它说它完成了”。这个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)