简体   繁体   English

在 python 中使用带条件的 yield from

[英]Using yield from with conditional in python

Let's say I have a generator like this:假设我有一个这样的生成器:

def a(data):
    for val in data:
        yield val

And let's say I want to wrap this generator in another generator, b , that only yields some of the values from a , depending on their value.让说,我想在另一个发电机,来包装这个发生器b ,只产生一些来自值的a ,这取决于它们的价值。 b should be able to forward values sent back from the caller to a . b应该能够将从调用者发回的值转发到a I know that the most current way of wrapping a generator in another generator is to use the yield from statement.我知道将生成器包装在另一个生成器中的最新方法是使用yield from语句。 Something like:就像是:

def b(data):
    yield from val = a(data) if val == "foo"

I know that syntax is wrong (it's just to get across the idea), so I'm wondering if there is a correct way to make yield from work with a conditional statement.我知道语法是错误的(只是为了理解这个想法),所以我想知道是否有正确的方法可以使用条件语句使工作yield from Or is there some other construct I should use?或者我应该使用其他一些构造吗?

As you said, yield from is only for the case where you want to pass everything from the wrapped generator through.正如您所说, yield from仅适用于您希望将包装生成器中的所有内容通过的情况。 If you don't want that, you need to manually iterate over the wrapped generator and do what you want:如果您不希望那样,您需要手动迭代包装的生成器并执行您想要的操作:

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

If you want to handle send , you need to handle that yourself too.如果你想处理send ,你也需要自己处理。 Here is a simple example that you can play around with to see what's going on:这是一个简单的示例,您可以使用它来查看发生了什么:

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

Basically in this example b "hides" the value 2 if it is yielded by a .基本上在这个例子中b “隐藏”了值 2 如果它是由a产生a (I adapted this from my answer to this question , which is similarly about wrapping generators, but in a slightly different way. You may find discussion there useful, though.) (我根据我对这个问题的回答改编了这个,这与包装生成器类似,但方式略有不同。不过,您可能会发现那里的讨论很有用。)

However, you would need to be very careful when doing this.但是,您在执行此操作时需要非常小心。 Since b may skip values from a , any caller that tries to send values into b may not get the expected results, because b may skip values in unexpected places.由于b可以跳过值a ,任何调用方试图send值到b可能无法获得预期的结果,因为b可能在意想不到的地方会跳过值。 In cases where you're using send , it often means the caller watches the generator for certain yielded values that communicate some information, then sends values back in response.在您使用send情况下,这通常意味着调用者会监视生成器中某些传递某些信息的生成值,然后将值发送回作为响应。 With b in the middle, this communication may get out of sync.如果b在中间,这种通信可能会不同步。 For instance, suppose a yields a "message" which b yields through to the caller, and the caller sends a response back, which b then sends to a .例如,假设a产生一条“消息”, b将其交给调用者,调用者发回响应,然后b将响应发送给a But suppose b swallows a 's response.但是假设b吞下a的响应。 This will cause problems for the caller.这会给调用者带来问题。 You may still be able to make it work, but it just means you have to be very careful in writing b to main any communication channels that are expected by the API of a .您可能仍然能够让它工作,但它只是意味着你必须以书面形式非常小心b通过的API中预期的任何主要的沟通渠道a

Since it looks like I can't incorporate a conditional onto a yield from , I solved this problem by handling the cases I cared about manually.由于看起来我无法将条件合并到yield from ,我通过手动处理我关心的情况解决了这个问题。 This is what I ended up with:这就是我最终的结果:

def a():
    data = get_data_somewhere()
    for val in data:
        yield val

def b():
    a_gen = a()
    val = next(a_gen)
    try:
        while True:
            if val == "foo":
                received = yield val
                val = a_gen.send(received)
            else:
                val = a_gen.send(None)
     except StopIteration:
         pass
     finally:
         del a_gen

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM