[Q] is 'yield from' syntax sugar for 'for'+'yield'?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Aug 14 09:43:22 EDT 2014


Makoto Kuwata wrote:

> Question about 'yield from'.
> 
> I understand that::
> 
>     yield from xs
> 
> is syntax suger of::
> 
>     for x in xs:
>       yield x

Not quite syntactic sugar. For simple cases, it does exactly the same thing.
For more complicated cases, no.

Suppose you have a generator:

def spam():
    yield "Spam!"
    yield "More spam!"
    yield "Delicious spam!!!"

and you have another generator which delegates to the spam generator:

def lunch1():
    for food in spam():
        yield food
    yield "plus a fried egg"


We can now re-write the generator using "yield from":

def lunch2():
    yield from spam()
    yield "plus a fried egg"

That saves one line of code. Big deal. Here, it is pure syntactic sugar.

There are more interesting cases, where "yield from" is more powerful than
the for-loop version. Here is an example with throw:

py> it = lunch1()  # Create an iterator.
py> next(it)
'Spam!'
py> it.throw(ValueError)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in lunch1
ValueError

Notice that the ValueError is raised inside lunch1(). There is no easy way
to push the exception back inside spam(). But with "yield from", it works:

py> it = lunch2()  # New "yield from" generator.
py> next(it)
'Spam!'
py> it.throw(ValueError)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in lunch2
  File "<stdin>", line 2, in spam
ValueError


Of course, spam() is free to catch the exception and perform processing.



> And::
> 
>     val = yield from xs
> 
> is same as::
> 
>     for x in xs:
>       ret = yield x
>     val = ret

No. This is closer to what happens:


# Not exactly this.
# This is a simplified version.
try:
    for x in xs:
        yield x
except StopIteration as err:
    val = err.value


The real version is much more complicated, 39 lines of code, and deals with
generator .close() and .throw() methods, error checking, and various other
issues. That is why "yield from" was added to Python. The simple case is
too simple to care about, the complicated cases are too complicated to
expect people to write their own solutions, so it was added to the
language.



-- 
Steven




More information about the Python-list mailing list