skip to navigation
skip to content

Python Wiki

Python Insider Blog

Python 2 or 3?

Help Fund Python

[Python resources in languages other than English]

Non-English Resources

Add an event to this calendar.

Times are shown in UTC/GMT.

Add an event to this calendar.

PEP: 3142
Title: Add a "while" clause to generator expressions
Version: f1428462ba69
Last-Modified:  2013-05-10 12:27:55 -0400 (Fri, 10 May 2013)
Author: Gerald Britton <gerald.britton at gmail.com>
Status: Rejected
Type: Standards Track
Content-Type: text/plain
Created: 12-Jan-2009
Python-Version: 3.0
Post-History: 
Resolution: http://mail.python.org/pipermail/python-dev/2013-May/126136.html

Abstract

   This PEP proposes an enhancement to generator expressions, adding a
   "while" clause to complement the existing "if" clause.


Rationale

   A generator expression (PEP 289 [1]) is a concise method to serve
   dynamically-generated objects to list comprehensions (PEP 202 [2]).
   Current generator expressions allow for an "if" clause to filter
   the objects that are returned to those meeting some set of
   criteria.  However, since the "if" clause is evaluated for every
   object that may be returned, in some cases it is possible that all
   objects would be rejected after a certain point.  For example:

       g = (n for n in range(100) if n*n < 50)

   which is equivalent to the using a generator function
   (PEP 255 [3]):

       def __gen(exp):
           for n in exp:
               if n*n < 50:
                   yield n
       g = __gen(iter(range(10)))

   would yield 0, 1, 2, 3, 4, 5, 6 and 7, but would also consider
   the numbers from 8 to 99 and reject them all since n*n >= 50 for
   numbers in that range.  Allowing for a "while" clause would allow
   the redundant tests to be short-circuited:

       g = (n for n in range(100) while n*n < 50)

   would also yield 0, 1, 2, 3, 4, 5, 6 and 7, but would stop at 8
   since the condition (n*n < 50) is no longer true.  This would be
   equivalent to the generator function:

       def __gen(exp):
           for n in exp:
               if n*n < 50:
                   yield n
               else:
                   break
       g = __gen(iter(range(100)))

   Currently, in order to achieve the same result, one would need to
   either write a generator function such as the one above or use the
   takewhile function from itertools:

       from itertools import takewhile
       g = takewhile(lambda n: n*n < 50, range(100))

   The takewhile code achieves the same result as the proposed syntax,
   albeit in a longer (some would say "less-elegant") fashion.  Also,
   the takewhile version requires an extra function call (the lambda
   in the example above) with the associated performance penalty.
   A simple test shows that:

       for n in (n for n in range(100) if 1): pass

   performs about 10% better than:

       for n in takewhile(lambda n: 1, range(100)): pass

   though they achieve similar results.  (The first example uses a
   generator; takewhile is an iterator).  If similarly implemented,
   a "while" clause should perform about the same as the "if" clause
   does today.

   The reader may ask if the "if" and "while" clauses should be
   mutually exclusive.  There are good examples that show that there
   are times when both may be used to good advantage. For example:

       p = (p for p in primes() if p > 100 while p < 1000)

   should return prime numbers found between 100 and 1000, assuming
   I have a primes() generator that yields prime numbers.

   Adding a "while" clause to generator expressions maintains the
   compact form while adding a useful facility for short-circuiting
   the expression.


Acknowledgements

   Raymond Hettinger first proposed the concept of generator
   expressions in January 2002.


References

   [1] PEP 289: Generator Expressions
       http://www.python.org/dev/peps/pep-0289/

   [2] PEP 202: List Comprehensions
       http://www.python.org/dev/peps/pep-0202/

   [3] PEP 255: Simple Generators
       http://www.python.org/dev/peps/pep-0255/


Copyright

   This document has been placed in the public domain.