混淆python屈服行为
今天我遇到了一个有趣的行为,混淆python屈服行为,python,generator,yield,Python,Generator,Yield,今天我遇到了一个有趣的行为,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
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之后才执行
使用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)
(我已经投了更高的票),但我看到您仍在为此进行斗争,所以让我们试试这个变体:
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)
现在让我们在Python3.x中运行它:
entering b.
0
calling b.
calling b resulted in temp = <generator object a.<locals>.b at 0x800ac9518>
return from b.
leaving b.
运行此命令将产生:
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.
您可能希望
从b(x+1)获得收益
调用b
不会运行主体。这不会因为是递归调用而改变。当你说“调用b(x+1)
不会调用b
”时,你从哪里调用它?如果它在a
之外,则不会被调用,因为它在范围之外,因此会执行函数调用;生成的生成器被忽略。不确定print(“calling b.”)
是否让您感到困惑?由于递归调用没有产生,因此也不会返回您可能期望的结果。。正如snake所指出的,我不明白如果调用b(x+1)(没有来自
的收益),那么为什么不打印“输入b.”呢?@handras,因为生成器是懒惰的。它已经创建,但是它的代码不会运行,直到您尝试获取它的下一个
元素。b(x+1)
除了返回一个生成器之外,不会执行任何操作;您仍然需要在该生成器上迭代,以便主体执行。这就是yield
和return
@handras之间的区别,因为生成器应该是这样工作的。每当调用next
时,它会停止并重新开始在yield语句处执行body。通常在被迭代的上下文中。
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.
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)