未执行的yield语句块函数运行?

时间:2017-02-08 09:29:26

标签: python generator yield

在下面简化的代码中,我想重用一个循环来先做一个准备并产生结果。

但是,准备(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

3 个答案:

答案 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)

在我看来,这里的实际解释是:

Python懒惰地评估if条件!

我会解释:

致电

foo(prepare=True)

就像这样,没有任何反应,尽管你可能期望bar(x)将被执行10次。但真正发生的事情是“没有人”#39;要求foo(prepare=True)调用的返回值,因此不评估if,但如果您使用foo的返回值,则可能会这样。

在对foo的第二次调用中,迭代返回值r,python必须评估返回值,它确实如此,并且我将显示:

<案例1
r = foo(prepare=True)
for x in r:
    pass

此处的输出是&#39; ENTER栏&#39; 9次。这意味着bar执行了9次。

<案例2
r = foo(prepare=False)
for x in r:
    pass

在这种情况下,没有&#39; ENTER栏&#39;按预期印刷。

总结一切,我会说:

例如:

# 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