将值发送到压缩的生成器

时间:2016-03-25 18:31:17

标签: python python-3.x generator

请考虑以下代码:

def g1():
    while True:
         yield 1

def g2():
    while True:
        yield 1
        yield 2

def g3():
    while True:
        yield 1
        yield 2
        yield 3

def G():
    # Zip all three generators
    genList = [g1(), g2(), g3()]
    Z = zip(*genList)
    yield from Z

# Iterate over the zip of all three generators
for i, g in zip(range(6), G()):
    print(g)

三个发电机g1,g2,g3都产生简单的数字,外部发电机G从这三个发电机的拉链产生。输出最终看起来像这样:

(1, 1, 1)
(1, 2, 2)
(1, 1, 3)
(1, 2, 1)
(1, 1, 2)
(1, 2, 3)

这就是我的预期:三个发生器被迭代过来"同时"也就是说在进入下一个之前我没有用尽第一个。

但是,我担心这有点像黑客。它只能工作,因为python中的zip类型实现了__next__方法,我猜想当我迭代G()生成器时会调用它。

但是假设我想向我的发电机发送值?即

# stop iteration if a negative value is sent
def g1():
    yield
    while True:
         input = yield 1
         if input < 0:
             break
...

# Create the generator and prime it
gen = G()
next(gen)

for i in zip(range(6)):
    g = gen.send(1)
    print(g)

gen.send(-1)

zip类型没有实现send功能,我不确定如何实现。

应该说我对生成器,协同程序以及更重要的python中新yield from语法的体验非常小。我真的担心我试图将这些语言功能塞进我的代码而不真正理解它的用途。

最终,这些函数的目的是返回对应于音频循环的字符串容器; g1生成器每次都会产生相同的循环,g2生成器会交替等等。这些变化会导致每次迭代时都返回一个不同的容器。

将每个循环视为自己的协程似乎是有意义的,因为它独立于其他循环,我想尝试利用一些语言功能,而不是提出一个不那么便携的面向对象的解决方案。

然而,也许我可以利用itertools中的某些东西,或者使用上下文管理器的东西。

1 个答案:

答案 0 :(得分:1)

send只是从yield恢复与next调用完全相同,但会传入一个值。如果您使用next代替send,就像发送None一样。

你可以用它来阻止你的发电机执行:

value = yield x
if value:
    return

只要您对其进行迭代(通过zip,for循环或next),它就会继续运行,但当您send处于任何真值时停止运行。但是,我想知道为什么你甚至想要。你认为在哪里需要做这样的事情?

另请注意itertools.cycle已经完成了您在此尝试的内容:

import itertools
c = itertools.cycle([1, 2, 3])
next(c), next(c), next(c), next(c)
# 1, 2, 3, 1, ...