Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a generator that yields values from any number of inner generators

I have a generator function generate which yields 5 random numbers one at a time. I need to be able to generate the numbers in two ways:

  1. Single generation, which means a single output of generate function
  2. Multiple generation, which means multiple execution of generate and yielding all the results together as a single (merged) flow

For that I wrote another function get_resource, which calls generate either once or using itertools.chain to run the generators one after another, but transparently to the caller.

My goal is to use get_resource function and produce the results in the same format (one list of numbers), regardless of single/multiple generations.

import itertools
import random


def get_resource(values=None):
    def resource_generator():
        if values:
            # run a generator for every value
            return itertools.chain(generate(value) for value in values)
        else:
            return generate('meh')

    return resource_generator()


def generate(value):
    for _ in range(5):
        yield random.randint(1, 101)


if __name__ == '__main__':
    # list() is used for convenience only, 
    # I still need the values one by one
    print list(get_resource())
    print list(get_resource([1, 2, 3]))

It prints:

[63, 22, 87, 2, 54]
[<generator object generate at 0x1089f7640>, <generator object generate at 0x1089f7690>, <generator object generate at 0x1089f76e0>]

While I need it to print:

[63, 22, 87, 2, 54]
[63, 22, 87, 2, 54, 1, 58, 79, 89, 77, 94, 99, 30, 30, 4]

I use python2.7

like image 556
Yury Fedorov Avatar asked Feb 19 '18 09:02

Yury Fedorov


People also ask

What are generators How does yielding work?

The done property of the generator object will be set to true and the value returned will be set to the value property of the generator object. All other yields will return undefined . If an error is thrown then also the execution of the generator will stop, yielding a generator itself.

Can a generator function have multiple yield expressions?

If you want to return multiple values from a function, you can use generator functions with yield keywords. The yield expressions return multiple values. They return one value, then wait, save the local state, and resume again.

Does generator contain yield statement?

Generator function contains one or more yield statements. When called, it returns an object (iterator) but does not start execution immediately. Methods like __iter__() and __next__() are implemented automatically. So we can iterate through the items using next() .

How many times Yield statement can be used in generator?

Unless your generator is infinite, you can iterate through it one time only. Once all values have been evaluated, iteration will stop and the for loop will exit. If you used next() , then instead you'll get an explicit StopIteration exception.


1 Answers

You can specify generator delegation using yield from starting with python-3.3+.

def get_resource(values=None):
    def resource_generator():
        if values:
            for value in values:
                yield from generate(value)
        else:
            yield from generate(None)

    return resource_generator()

Now,

>>> list(get_resource([1, 2, 3]))
[46, 99, 97, 1, 42, 79, 69, 9, 45, 25, 77, 56, 54, 7, 41]
like image 105
cs95 Avatar answered Nov 10 '22 18:11

cs95