Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How two consecutive yield statement work in python?

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!

like image 402
unnobtainium Avatar asked Sep 27 '17 05:09

unnobtainium


People also ask

How do you do multiple yields in Python?

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.

Can you yield two values Python?

Conclusion. Like other programming languages, Python can return a single value, but in this, we can use yield statements to return more than one value for the function. The function that uses the yield keyword is known as a generator function.

Can you yield multiple times Python?

The yield statement can run multiple times. The return statement is placed inside a regular Python function. The yield statement converts a regular function into a generator function.

How yield function works in Python?

Yield is a keyword in Python that is used to return from a function without destroying the states of its local variable and when the function is called, the execution starts from the last yield statement. Any function that contains a yield keyword is termed a generator. Hence, yield is what makes a generator.


2 Answers

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 
like image 116
Dimitris Fasarakis Hilliard Avatar answered Sep 29 '22 04:09

Dimitris Fasarakis Hilliard


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
like image 29
Challenger5 Avatar answered Sep 29 '22 05:09

Challenger5