[Python-ideas] Add "while" clauses to generator expressions

Gerald Britton gerald.britton at gmail.com
Sat Jan 10 16:35:49 CET 2009


I've been using Python generators for a while now.  e.g.

a=(i for i in range(10))

a.next()
a.next()
...etc.

I also find the "if" clause handy:

a = (i for i in range(10) if i%2==0)

(I know that range(0,12,2) will do the same thing, but it's the idea I
like, especially for more complex predicates.)

I would like to know if anyone has thought of adding a "while" clause
as well, like this:

a = (i for i in range(100) while i <=50)

(Again, this could be done with range(0,51) but then the predicate can
be more complicated.)

Why would this be helpful?  Consider the "in ..." part of the
generator.  You could be referring to something that is ordered --
sorted names for example.  Then you might want to stop your iterator
when you reach "Morgan" so you would like to write:

name = (n for n in names while n <= "Morgan")
name.next()
...etc...

Of course,

name = (n for n in names if n <= "Morgan")

will work, but it will look at every item in "names."  Since "names"
is sorted, this is a waste of time.  Imagine you want to stop at
"Baker".  Your "if" clause will look at and discard most names in the
list, assuming a normal distribution of English names.

Now, you could do the same thing with a generator function:

def leMorgan(names):
  i = 0
  while names[i] <= "Morgan":
    yield names[i]
    i+=1

and use it like this:

name=leMorgan(names)
name.next()
...etc...

but I think that adding a while clause to the generator expression is
simpler and clearer (and it keeps it all in one place!)

I know that this is functionally equivalent to the takewhile function
in itertools and my motivation is the same.   I just think that this
could be done nicely within the context of the existing syntax. This
is also convenient when the "in ..." clause refers to another
(possibly infinite) generator.  For a simple example, suppose I want
to run through some natural numbers.  I can write an infinte generator
function like this:

def genN(n=0):
  while 1:
    yield n
    n+=1

Then, I might use this in another generator:

p = (n for n in genN() if prime(n) while n <= 100)

to get the prime numbers under 100 (assuming I have a predicate
"prime" that works as one would hope).  Of course you could do this
with range(101) instead of genN, but this is just an example to
demonstrate the idea.

Without the "while" clause, this will not work:

p = (n for n in genN() if prime(n) if n <= 100)

This will actually NEVER terminate, since EVERY item in genN() (which
is an infinite generator) will be tested for <= 100.

So...What do others think?  Is this a loony idea?  Is there a better
way?  Also, can anyone think of a similarly syntax to replicate the
dropwhile function?



More information about the Python-ideas mailing list