Question

I'm making a Python irc bot. For some reason the yield statement in my join() method makes it skip the method altogether, but if I replace it with a return it works fine. However, I need to yield an error per each unsuccessful join attempt.

I have a join method of the bot that returns a server error command code response if the join is unsuccessful for some reason. It's None if the bot joins successfully.

unsuccessful = bot.join(channels)

I would be able to do:

if unsuccessful:
    for error in unsuccessful:
        print(error)

The join method looks like this

def join(self, channels):
    chan_errors = range(471, 480)  # See RFC for commands 471-479

    if isinstance(channels, str):
        channels = [channels,]

    for channel in channels:
        self.send('JOIN %s' % channel)
        for response in self.get_response('JOIN', chan_errors):  # Verify
            if response.command in chan_errors:
                channels.remove(channel)
                yield response
    self.channels.append(channels)

If I switch the "yield response" with "return response" it runs the method.

The get_response method looks like

def get_response(self, commands, terminators=None):
    for msg in self.msg_gen():
        self.handle(msg)
        if msg.command in commands:
            if terminators is None:
                return msg
            yield msg
        if msg.command in terminators:
            return msg

It receives messages from a message generator. The commands are the server command the caller is looking for and the terminators drop out of the generator when one is found. It's sort of like a coroutine.

Does anyone know what is happening here?

Was it helpful?

Solution

By putting a yield statement in the join method, you're making it a generator. Calling a generator method just creates a generator function; you need to iterate through it to get data. However, since execution inside a generator stops every time it hits a yield statement, you need to exhaust all of its contents if you want it to fully run.

This way your code runs all the way through:

join_gen = bot.join(channels)
for error_msg in join_gen:
    print error_msg

Generators in the Python 2 docs

I'm not sure a generator is a good option for you here though. You might be better served returning response right when you have the first error, or if you want to go through all the channels, append each error response to an error list and return that list when you're done.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top