1

Consider the following (non-working) example code:

class MyGenerator:
    def test_gen(self):
        for i in range(1,5):
            if i % 2:
                self.foo(i)
            else:
                self.bar(i)

    def foo(self, i):
        yield i

    def bar(self, i):
        yield i**2

g = MyGenerator()
for i in g.test_gen():
    print i

This will not work, because test_gen has no yield and is no longer a generator function. In this small example I could just return the values from foo and bar and put the yield into test_gen, however I have a case where that's not possible. How can I turn test_gen into a generator function again?

2 Answers 2

5

You need to loop over the results of the delegated generators and yield those:

def test_gen(self):
    for i in range(1,5):
        if i % 2:
            for res in self.foo(i):
                yield res
        else:
            for res in self.bar(i):
                yield res

If you are using Python 3.3 or up, you'd use the yield from expression to do proper generator delegation:

def test_gen(self):
    for i in range(1,5):
        if i % 2:
            yield from self.foo(i)
        else:
            yield from self.bar(i)

Both re-introduce yield into the function, once again making it a generator function.

Sign up to request clarification or add additional context in comments.

2 Comments

Ha, the Python 3 way is exactly what I was looking for! Sweet and concise. Unfortunately I'm on Python 2.7 :-(
In this special example, the subgenerator will just yield a simple item before exhausting, so the yield from examples are fine. But people using it have to attempt they do yield up to exhaustion of the sub-generators, not a single item - and only after that the controls comes back to the primary generator. (otherwise they would not be distinguishable from a plain yield)
0

why not just:

class MyGenerator:
    def test_gen(self):
        for i in range(1,5):
            if i % 2:
                yield next(self.foo(i))
            else:
                yield next(self.bar(i))

    def foo(self, i):
        yield i

    def bar(self, i):
        yield i**2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.