为什么“yield from”在all()或any()中没有按预期工作?

时间:2015-11-16 15:42:02

标签: python python-3.x

今天我正在调试一个奇怪的问题。这个程序很复杂,但是我把这个部分简化为只有几条线来重现奇怪的行为。

在示例中,我连续三次测试随机生成器。如果所有三个测试都返回True,则测试完成。如果没有,必须从头开始重复测试。

函数func1正常工作。具有func2的函数any()应该等同于func1,但事实并非如此。它不起作用,它会产生错误。 func3也被打破,这是一个无限繁忙的循环。

问题出在哪里?以yield from之外的其他方式使用value = yield from ...是合法的吗?我没有在文档中找到任何内容(到目前为止):

  

当使用yield from时,它将提供的表达式视为a   subiterator。该子转换器生成的所有值都将被传递   直接到当前生成器方法的调用者。

# Python 3.3 or newer
import random

def yield_random():
    if random.choice((True, False)):
        yield "OK"
        return True
    return False

def func1():
    # only this function works fine
    ok3 = False
    while not ok3:
        for i in range(3):
            ok1 = yield from yield_random()
            if not ok1:
                print("-- not ok")
                break
        else:
            print("All 3 ok !")
            ok3 = True

def func2():
    # does not work
    ok3 = False
    while not ok3:
        ok3 = all((yield from yield_random()) for i in range(3))
    print("All 3 ok !")

def func3():
    # does not work
    while any(not (yield from yield_random()) for i in range(3)):
        print("-- not ok")
    print("All 3 ok !")

for x in func1():
    print("got:", x)

1 个答案:

答案 0 :(得分:2)

func1是返回生成器的函数,而func2func3是常规函数:

>>> type(func1())
<class 'generator'>
>>> type(func2())
All 3 ok !
<class 'NoneType'>

那是因为:

ok3 = all((yield from yield_random()) for i in range(3))

实际上相当于:

def _gen():
    for i in range(3):
        r = yield from yield_random()
        yield r
ok3 = all(_gen())

由于yield from语句封装在生成器中,因此此代码不会产生任何结果。您甚至可以在控制台中的函数外部运行它,例如:

>>> all((yield from yield_random()) for i in range(3))
False

虽然它可能不符合您的期望:

>>> list((yield from yield_random()) for i in range(3))
['OK', True, False, False]