[Python-ideas] [Python-Dev] yield * (Re: Missing operator.call)

Steven D'Aprano steve at pearwood.info
Sun Feb 8 09:14:46 CET 2009

Leif Walsh wrote:

> I still don't understand why such a construct is necessary.  Is
>>>> for elt in iterable:
>>>>     yield elt
> really all that bad?  Maybe it's a little silly-looking, but at least
> it's easy to understand and not _that_ hard to type....

It's not just silly looking, it's the same construct used repeatedly, in 
many different places in code. It is a basic principle of programming 
that anytime you have blocks of code that are almost identical, you 
should factor out the common code into it's own routine. See "Don't 
Repeat Yourself" and "Once And Only Once" for similar ideas:


Consider a pure Python implementation of itertools.chain:

def chain(*iterables):
     for it in iterables:
         for elt in it:
             yield elt

The double for loop obscures the essential nature of chain. From 

"Return a chain object whose .next() method returns elements from the
first iterable until it is exhausted, then elements from the next
iterable, until all of the iterables are exhausted."

The emphasis is on iterating over the sequence of iterables, not 
iterating over each iterable itself. This is one place where explicit is 
*not* better than implicit, as the inner loop exposes too much of the 
internal detail to the reader. Instead, chain() could be better written 
as this:

def chain(*iterables):
     for it in iterables:
         yield from it

Naturally you can use map and filter to transform the results:

yield from map(trans, filter(expr, it))

The advantage is even more obvious when married with a generator expression:

yield from (3*x for x in seq if x%2 == 1)

instead of:

for x in seq:
     if x%2 == 1:
         yield 3*x


for y in (3*x for x in seq if x%2 == 1):
     yield y

I'm +1 on this suggestion, especially since it requires no new keywords.


More information about the Python-ideas mailing list