Please find below PEP 3142: Add a "while" clause to generator expressions. I'm looking for feedback and discussion.
PEP: 3142 Title: Add a "while" clause to generator expressions Version: $Revision: 68715 $ Last-Modified: $Date: 2009-01-18 11:28:20 +0100 (So, 18. Jan 2009) $ Author: Gerald Britton <gerald.brit...@gmail.com> Status: Draft Type: Standards Track Content-Type: text/plain Created: 12-Jan-2009 Python-Version: 3.0 Post-History: 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. Of course, this could also be achieved like this: p = (p for p in (p for p in primes() if p > 100) while p < 1000) which is syntactically simpler. Some may also ask if it is possible to cover dropwhile() functionality in a similar way. I initially thought of: p = (p for p in primes() not while p < 100) but I am not sure that I like it since it uses "not" in a non-pythonic fashion, I think. Adding a "while" clause to generator expressions maintains the compact form while adding a useful facility for short-circuiting the expression. Implementation: I am willing to assist in the implementation of this feature, although I have not contributed to Python thus far and would definitely need mentoring. (At this point I am not quite sure where to begin.) Presently though, I would find it challenging to fit this work into my existing workload. 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. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:
PEP: 3142 Title: Add a "while" clause to generator expressions Version: $Revision: 68715 $ Last-Modified: $Date: 2009-01-18 11:28:20 +0100 (So, 18. Jan 2009) $ Author: Gerald Britton <gerald.brit...@gmail.com> Status: Draft Type: Standards Track Content-Type: text/plain Created: 12-Jan-2009 Python-Version: 3.0 Post-History: 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. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End:
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com