How to yield results from a nested generator function?

33,276

Solution 1

Can't believe I missed this; The answer is to simply return the generator function with suitable arguments applied:

import time

def GeneratorFunction(max_val):
    for i in range(0,max_val):
        time.sleep(1)
        yield "String %d"%i

def SmallGenerator():
    return GeneratorFunction(3) # <-- note the use of return instead of yield

for s in SmallGenerator():
    print s

Solution 2

You may have to use the new yield from, available since Python 3.3, known as “delegated generator”.

If I understood the question correctly, I came to the same issue, and found an answer elsewhere.

I wanted to do something like this:

def f():

    def g():

        do_something()
        yield x
        …
        yield y

    do_some_other_thing()
    yield a
    …
    g()  # Was not working.
    yield g()  # Was not what was expected neither; yielded None.
    …
    yield b

I now use this instead:

yield from g()  # Now it works, it yields x and Y.

I got the answer from this page: Python 3: Using "yield from" in Generators - Part 1 (simeonvisser.com).

Solution 3

Came here looking for a different form of "nested yield" and finally found the hidden answer. Might not be the best but it works.

I was wanting to yield through a registry tree and here is the solution.

        def genKeys(key):
            for value in key.values():
                yield value
            for subkey in key.subkeys():
                print(subkey)
                for x in genKeys(subkey): #this is the trick
                    continue
Share:
33,276
Jon Cage
Author by

Jon Cage

A Computer Systems Engineer based in the UK

Updated on July 05, 2022

Comments

  • Jon Cage
    Jon Cage almost 2 years

    I have a function which yields results as it downloads them. For the purposes of this question, lets say I yield a sting once every second but I want a convenience function to wrap my generator:

    import time
    
    def GeneratorFunction(max_val):
        for i in range(0,5):
            time.sleep(1)
            yield "String %d"%i
    
    def SmallGenerator():
        yield GeneratorFunction(3)
    
    for s in SmallGenerator():
        print s
    

    ...why doesn't that just print the 5 strings I'm expecting? Instead it appears to return the generator functio:

    <generator object GeneratorFunction at 0x020649B8>
    

    How can I get this to yield the strings as a normal generator function would?

  • DonkeyKong
    DonkeyKong over 4 years
    unless your function reads: yield GeneratorFunction(3) yield GeneratorFunction(2). In this case a return would not work. Yield From fulfills this requirement.
  • krubo
    krubo over 4 years
    Looks like this yields the top-level values, and recursively prints subkeys, but doesn't recursively yield anything. Or did I miss something?
  • Bikash Gyawali
    Bikash Gyawali over 3 years
    but if you are using return inside def SmallGenerator():, it is not a nested generator function anymore?? or is it??