How two consecutive yield statement work in python?

14,172

Solution 1

The same way a single yield works.

You can have as many yields as you like in a generator, when __next__ is called on it, it will execute until it bumps into the next yield. You then get back the yielded expression and the generator pauses until it's __next__ method is invoked again.

Run a couple of next calls on the generator to see this:

>>> g = make_iterables_to_chain()  # get generator
>>> next(g) # start generator, go to first yield, get result
[1, 2, 3]
>>> next(g) # resume generator, go to second yield, get result
['a', 'b', 'c']
>>> # next(g) raises Exception since no more yields are found 

Solution 2

A generator effectively allows a function to return multiple times. Every time a yield statement is executed, the value is returned to the caller, and the caller can continue the function's execution.

Usually, they are used as iterables in for loops.

The following function increments every element in an iterable by an amount:

def inc_each(nums, inc):
    for i in nums:
        yield i + inc

Here is an example of the usage:

gen = inc_each([1, 2, 3, 4], 100)
print(list(gen)) # [101, 102, 103, 104]

list is used here to convert an arbitrary iterable (in this case a generator) to a list.

The function you describe executes two yield statements:

def make_iterables_to_chain():
    yield [1, 2, 3]
    yield ['a', 'b', 'c']

If you call it, it returns a generator that, if iterated through, yields the lists [1, 2, 3] and ['a', 'b', 'c'].

gen = make_iterables_to_chain()
print(list(gen)) # [[1, 2, 3], ['a', 'b', 'c']]

itertools.chain.from_iterable will take a (possibly infinite) iterable of iterables and "flatten" it, returning a (possible infinite) iterable as the result.

Here is a way it could be implemented:

def from_iterable(iterables):
    for iterable in iterables:
        for i in iterable:
            yield i
Share:
14,172

Related videos on Youtube

unnobtainium
Author by

unnobtainium

I am a not a hardcore gamer but I game when I get time. Game is one of my many hobbies. import game while True: game.Letsgame()

Updated on September 26, 2022

Comments

  • unnobtainium
    unnobtainium over 1 year

    I stumble upon this code from pymotw.com in merging and splitting section.

    from itertools import *
    
    
    def make_iterables_to_chain():
        yield [1, 2, 3]
        yield ['a', 'b', 'c']
    
    
    for i in chain.from_iterable(make_iterables_to_chain()):
        print(i, end=' ')
    print()
    

    I can not understand how make_iterables_to_chain() is working. It contains two yield statement, how does it work? I know how generators work but there but there was only single yield statement.

    Help, please!

  • unnobtainium
    unnobtainium over 6 years
    do you mean that when first time make_iterables_to_chain() is called it gives the first yield statement i.e. [1,2,3] and when second time it is called the second yield statement is called i.e. ['a', 'b', 'c']
  • Challenger5
    Challenger5 over 6 years
    @ispeedster Generator expressions actually have an additional layer of indirection. When you call make_iterables_to_chain, it returns a generator object that can be iterated through using iter() and next() (though this is usually handled automatically by for loops). So the function itself is only ever called once, but the resulting object can be iterated through and can yield multiple values.