[Python-Dev] For/while/if statements/comprehension/generator expressions unification
ncoghlan at gmail.com
Tue Sep 20 10:58:24 CEST 2005
Alexander Myodov wrote:
> To increase my understanding of Python-way, can you (or someone else)
> explain the reasons why such proposals were rejected?
I wasn't around for the discussion Josiah refers to, but I would guess it is
because they don't improve the power or readability of the language, and may
in fact be significantly less readable than simply nesting the corresponding
In particular, with the current syntax, the local variables bound by the for
statement are clearly visible immediately after the 'for' keyword. If multiple
instances of the keyword were allowed in a single for statement, the names
being bound could be hidden after an arbitrarily complex expression.
This 'hidden local' problem is one of the concerns with the current behaviour
where list comprehensions make their loop variables visible in the surrounding
scope (this behaviour will be fixed in Py3k, and was deliberately avoided for
> 1. Bring 'if'-s from generator/comprehension 'for' syntax to 'for'
> statement. That's truly inconsistent that one may write
> list2 = [i for i in list if cond(i)]
> but cannot write
> for i in list if cond(i):
No, instead you write:
for i in list:
The order of execution of loops and conditionals is entirely unambiguous, as
it is shown explicitly by the nesting. Python has never been shy about
requiring vertical and horizontal whitespace at the statement level in order
to make the sequence of control flow more explicit.
The rules are different for list comprehensions and generator expressions,
because whitespace is only used to delimit tokens inside expressions, rather
than being a token in its own right as it can be at the statement level.
However, the order of execution of these expressions can be disambiguated by
conversion to the nested statement version of the same code.
> 2. Bring "several for-s in a row" ability from
> generators/comprehensions to the statement (and expand it to "several
> for-s and if-s", of course). We can write
> list2 = [f(i, j) for i in list1 for j in list2]
> but cannot write
> for i in list1 for j in list2:
> yield f(i, j)
> That looks inconsistent as well.
If the apparent inconsistency genuinely bothers you, you can always write the
statement version as:
for x in (f(i, j) for i list1 for j in list2):
Note that this preserves the fact that only 'x' is bound in the surrounding
scope, and this name is prominent in the 'for' statement.
> Yes, for this little case we could do some kind of cross, but what if
> there are more loops, and/or some of them require filtering by if-s?
Then readers of the code could probably be helped out if some of the
intermediate steps were named to explain what's going on. Alternately, just
use a genexp as I show above.
> 3. Bring 'while' into the loops, both statements and iterators. Now no
> need to worry about "hidden-goto" 'break', especially for the cases of
> nested loops, while it can be easily checked right inside the looping
'break' is no more a 'hidden-goto' than any other form of non-sequential
control flow (like say, conditionals or loops) is a goto. The problem with
having an actual goto is that it can go *anywhere*, leading to a high chance
of writing spaghetti code - this is not the case when using break, as you
can't go anywhere other than the statement immediately following the loop.
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
More information about the Python-Dev