在下面简化的代码中,我想重用一个循环来先做一个准备并产生结果。
但是,准备(bar()
)函数永远不会执行。
yield语句是否改变了函数的流程?
def bar(*args,**kwargs):
print("ENTER bar")
pass
def foo(prepare=False):
print("ENTER foo")
for x in range(1,10):
if prepare:
bar(x)
else:
yield x
foo(prepare=True)
r = foo(prepare=False)
for x in r:
pass
答案 0 :(得分:2)
因为foo
定义包含一个yield,所以即使你把它称为普通函数,它也不会像普通函数那样运行(例如foo(prepare=True)
)。
使用任何参数运行foo()
将返回生成器对象,适合迭代。在尝试迭代该生成器对象之前,定义的主体不会运行。
new coroutine syntax会在关键字的开始处放置一个关键字,以便自然界中的更改不会隐藏在函数体内。
答案 1 :(得分:0)
问题是,使用yield
语句会将函数更改为返回生成器并更改函数的行为。
基本上这意味着在调用生成器的.next
函数时,函数执行yield
或函数终止(在这种情况下,它会引发StopIteration
异常)。
因此,您应该做的是确保即使未达到yield
语句也要对其进行迭代。像:
r = foo(prepare=True)
for x in r:
pass
在这种情况下,循环将立即终止,因为没有到达yield
语句。
答案 2 :(得分:-2)
在我看来,这里的实际解释是:
if
条件!我会解释:
致电
时foo(prepare=True)
就像这样,没有任何反应,尽管你可能期望bar(x)
将被执行10次。但真正发生的事情是“没有人”#39;要求foo(prepare=True)
调用的返回值,因此不评估if
,但如果您使用foo
的返回值,则可能会这样。
在对foo
的第二次调用中,迭代返回值r
,python必须评估返回值,它确实如此,并且我将显示:
r = foo(prepare=True)
for x in r:
pass
此处的输出是' ENTER栏' 9次。这意味着bar
执行了9次。
r = foo(prepare=False)
for x in r:
pass
在这种情况下,没有' ENTER栏'按预期印刷。
总结一切,我会说:
在某些情况下,Python会执行Lazy Evaluation,one of them is the if
statement。
并非所有内容都在Python中延迟评估,
例如:
# builds a big list and immediately discards it
sum([x*x for x in xrange(2000000)])
<强> VS 强>
# only keeps one value at a time in memory
sum(x*x for x in xrange(2000000))
关于python中的懒惰和热切评估,请继续阅读here。