在python中使用带有条件的yield

时间:2015-12-03 20:29:59

标签: python generator

让我们说我有这样的发电机:

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

让我们说我想将这个生成器包装在另一个生成器b中,它只生成a中的一些值,具体取决于它们的值。 b应该能够将从调用方发回的值转发给a。我知道在另一个生成器中包装生成器的最新方法是使用yield from语句。类似的东西:

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

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

2 个答案:

答案 0 :(得分:1)

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

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

如果你想处理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

在此示例中,基本上b“隐藏”值{2},如果它由a产生。 (我从我对this question的回答中对此进行了调整,这类似于包装生成器,但方式略有不同。但是,你可能会发现那里的讨论很有用。)

但是,这样做时你需要非常小心。由于b可能会跳过a中的值,因此尝试将send值转换为b的任何来电者都可能无法获得预期结果,因为b可能会跳过意外的地方。在您使用send的情况下,通常意味着调用者会监视生成器以获取某些信息,这些值会传递某些信息,然后将值作为响应发送回来。如果中间为b,则此通信可能会不同步。例如,假设a产生一条“消息”,b向呼叫者发送消息,然后呼叫者发回一个响应,然后b发送给a。但假设b吞下a的回复。这将给调用者带来问题。您仍然可以使其工作,但这只是意味着您必须非常谨慎地编写b来构建a API所期望的任何通信渠道。

答案 1 :(得分:0)

由于看起来我无法将条件合并到<input type="button" onclick="printDiv('printableArea')" value="print a div!" /> ,我通过处理手动关注的案例解决了这个问题。这就是我最终的结果:

yield from