Python生成器发送:发送后不产生新值

时间:2014-02-25 23:59:54

标签: python generator yield coroutine yield-keyword

这是一个奇怪的问题所以我会解释:

我有一个这样的生成器,它充当IRC服务器的生成器前端:

def irc_iter(): # not the real code, simplified
    msgs = get_msgs()
    for msg in msgs:
        if is_ping(msg):
            pong()
        else:
            to_send = yield msg
            for s in to_send:
                send(s)

理论上,这应该让我做一些很酷的事情,比如:

server = connect()
for line in server:
       if should_respond(line):
           server.send('WOW SUCH MESSAGE')

然而,有一个障碍:generator.send 也会产生下一个值。这意味着server.send也给了我下一条消息...我希望像所有其他消息一样处理这些消息,产生为line

我知道我可以用一种丑陋的方式解决这个问题,只是在收到一个发送后产生一个垃圾值,但我试图保持我的代码优雅,这是相反的。有没有办法告诉生成器我还不想要一个新值呢?

感谢。

2 个答案:

答案 0 :(得分:1)

我也刚遇到这个问题,也没有发现比虚拟yield ...更好的东西

所以在您的生成器代码中:

        # Input
        input_value = yield
        if input_value is None:
            # Handle situation if someone used your generator in a wrong way
            sys.exit(-1)
        yield "DUMMY YIELD JUST STOP HERE!!!"

在客户端代码中:

while True:
    values = next(my_generator)
    ...
    if values == 'INPUT_NEEDED':
        # At this point you realize it's input time
        next(my_generator) # Rewind to the input point
        my_generator.send(12345) # Returns "DUMMY YIELD JUST STOP HERE!!!"
        continue
    # Continue the main loop

答案 1 :(得分:0)

看起来问题来自于每次迭代调用生成器两次,一次使用.send(None)(在for循环中)和一次使用.send(response)

如果for循环可以迭代.send()而不是.next(),这将是一个简单的修复,但是我不熟悉任何方法来实现它(pep342中的可选扩展continue语句?)将它包装在另一个生成器中(可能使用队列将值推送到.next()调用的.send())。但最简单的解决方案可能是:

server = connect()
response = None 
try:
    while True:
        line = server.send(response)
        response = None
        if should_respond(line):
            response ='WOW SUCH MESSAGE'
except StopIteration:
    pass