在Python中使用yield from with条件

Lat*_*der 10 python generator

假设我有一个这样的生成器:

def a(data):
    for val in data:
        yield val
Run Code Online (Sandbox Code Playgroud)

假设我想将此生成器包装在另一个生成器 中,b该生成器仅生成 中的一些值a,具体取决于它们的值。b应该能够将从调用者发回的值转发到a. 我知道将一个生成器包装在另一个生成器中的最新方法是使用该yield from语句。就像是:

def b(data):
    yield from val = a(data) if val == "foo"
Run Code Online (Sandbox Code Playgroud)

我知道语法是错误的(这只是为了理解这个想法),所以我想知道是否有正确的方法来使用yield from条件语句。或者我应该使用其他一些构造?

Bre*_*arn 6

正如您所说,yield from仅适用于您想要传递包装生成器中的所有内容的情况。如果您不希望这样,您需要手动迭代包装的生成器并执行您想要的操作:

def b(data):
    for value in a(data):
        if some_condition(value):
            yield value
        # otherwise don't yield it.
Run Code Online (Sandbox Code Playgroud)

如果你想处理send,你也需要自己处理。这是一个简单的示例,您可以尝试看看发生了什么:

def a():
    sent = yield "Begin"
    for x in [1, 2, 3]:
        if sent:
            sent = yield "You sent {0}".format(sent)
        else:
            sent = yield x

def b():
    gen = a()
    val = yield next(gen)
    while True:
        wrappedVal = gen.send(val)
        if wrappedVal == 2:
            continue
        val = yield wrappedVal
Run Code Online (Sandbox Code Playgroud)

基本上,在此示例中,b如果值 2 由 产生,则“隐藏”值 2 a(我根据我对这个问题的回答进行了改编,该问题与包装生成器类似,但方式略有不同。不过,您可能会发现那里的讨论很有用。)

但是,执行此操作时您需要非常小心。由于b可能会跳过 中的值a,因此任何尝试将send值放入 的调用者b可能无法获得预期的结果,因为b可能会跳过意外位置的值。在您使用的情况下send,这通常意味着调用者会监视生成器以获取传达某些信息的某些生成值,然后将值发送回作为响应。如果处于b中间,这种通信可能会不同步。例如,假设a产生一条“消息”,该消息b传递给调用者,调用者发回响应,b然后将响应发送到a。但假设b燕子a的反应。这会给调用者带来问题。您也许仍然能够使其工作,但这只是意味着您必须非常小心地b编写a.