28

I stumble upon this code frompymotw.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 singleyield statement.

Help, please!

Dimitris Fasarakis Hilliard's user avatar
Dimitris Fasarakis Hilliard
162k35 gold badges282 silver badges265 bronze badges
askedSep 27, 2017 at 5:42
unnobtainium's user avatar
3
  • There probably was only one yield statement, but was it not in a loop?CommentedSep 27, 2017 at 6:30
  • there are two. I just didn't understand the fundamental of two yield. I thought once yield is encountered it does not go to other yield, but that is not the case.CommentedSep 27, 2017 at 10:27
  • The canonical question for this has hundreds of links, millions of views and is the single most upvoted question in the Python tag. The first example given in the question uses twoyield statements, so that can't be an objection (even though the logical application is straightforward anyway). It's mystifying to me that nobody noticed such an obvious duplicate closure at the time, let alone letting it sit around for 5 years.CommentedOct 7, 2022 at 7:12

3 Answers3

28

The same way a singleyield works.

You can have as manyyields 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 ofnext 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
answeredSep 27, 2017 at 5:49
Dimitris Fasarakis Hilliard's user avatar
Sign up to request clarification or add additional context in comments.

Comments

6

A generator effectively allows a function to returnmultiple times. Every time ayield 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 infor 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
answeredSep 27, 2017 at 5:52
Challenger5's user avatar

2 Comments

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']
@ispeedster Generator expressions actually have an additional layer of indirection. When you callmake_iterables_to_chain, it returns agenerator object that can be iterated through usingiter() andnext() (though this is usually handled automatically byfor loops). So the function itself is only ever called once, but the resulting object can be iterated through and can yield multiple values.
-1

Just adding on top of the previous answers that when using such code:

def my_yield_function():  yield 1  yield 'test'  yield 2  yield true

You can unpack all the value with such code:

w,x,y,z = my_yield_function()
answeredOct 7, 2022 at 6:45
DueSouth's user avatar

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.