[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:
http://c2.com/cgi/wiki?OnceAndOnlyOnce
http://c2.com/cgi/wiki?DontRepeatYourself
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
help(itertools.chain):
"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
or
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.
--
Steven
More information about the Python-ideas
mailing list