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
yield
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. – Fashionable