PEP-xxx: Unification of for statement and list-comp syntax
me+python at modelnine.org
Sun May 21 17:11:24 CEST 2006
The following PEP tries to make the case for a slight unification of for
statement and list comprehension syntax.
Comments appreciated, including on the sample implementation.
Title: Unification of for-statement and list-comprehension syntax
Author: Heiko Wundram <me at modelnine.org>
Type: Standards Track
Post-History: 21-May-2006 17:00 GMT+0200
When list comprehensions were introduced, they added the ability
to add conditions which are tested before the expression which is
associated with the list comprehension is evaluated. This is
often used to create new lists which consist only of those items
of the original list which match the specified condition(s). For
[node for node in tree if node.haschildren()]
will create a new list which only contains those items of the
original list (tree) whose items match the havechildren()
condition. Generator expressions work similarily.
With a standard for-loop, this corresponds to adding a continue
statement testing for the negated expression at the beginning of
the loop body.
As I've noticed that I find myself typing the latter quite often
in code I write, it would only be sensible to add the corresponding
syntax for the for statement:
for node in tree if node.haschildren():
<do something with node>
as syntactic sugar for:
for node in tree:
if not node.haschildren():
<do something with node>
There are several other methods (including generator-expressions or
list-comprehensions, the itertools module, or the builtin filter
function) to achieve this same goal, but all of them make the code
longer and harder to understand and/or require more memory, because
of the generation of an intermediate list.
The implementation of this feature requires changes to the Python
grammar, to allow for a variable number of 'if'-expressions before
the colon of a 'for'-statement:
for_stmt: 'for' exprlist 'in' testlist_safe ('if' old_test)* ':'
suite ['else' ':' suite]
This change would replace testlist with testlist_safe as the
'in'-expression of a for statement, in line with the definition of
list comprehensions in the Python grammar.
Each of the 'if'-expressions is evaluated in turn (if present), until
one is found False, in which case the 'for'-statement restarts at the
next item from the generator of the 'in'-expression immediately
(the tests are thus short-circuting), or until all are found to be
True (or there are no tests), in which case the suite body is executed.
The behaviour of the 'else'-suite is unchanged.
The intermediate code that is generated is modelled after the
byte-code that is generated for list comprehensions:
for x in range(10) if x == 1:
2 0 SETUP_LOOP 42 (to 45)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (10)
9 CALL_FUNCTION 1
>> 13 FOR_ITER 28 (to 44)
16 STORE_FAST 0 (x)
19 LOAD_FAST 0 (x)
22 LOAD_CONST 2 (1)
25 COMPARE_OP 2 (==)
28 JUMP_IF_FALSE 9 (to 40)
3 32 LOAD_FAST 0 (x)
37 JUMP_ABSOLUTE 13
>> 40 POP_TOP
41 JUMP_ABSOLUTE 13
>> 44 POP_BLOCK
>> 45 LOAD_CONST 0 (None)
where all tests are inserted immediately at the beginning of the
loop body, and jump to a new block if found to be false which pops
the comparision from the stack and jumps back to the beginning of
the loop to fetch the next item.
The changes are backwards-compatible, as they don't change the
default behaviour of the 'for'-loop. Also, as the changes that
this PEP proposes don't change the byte-code structure of the
interpreter, old byte-code continues to run on Python with this
A sample implementation (with updates to the grammar documentation
and a small test case) is available at:
This document has been placed in the public domain.
More information about the Python-list