[Python-Dev] For/while/if statements/comprehension/generator expressions unification

Nick Coghlan 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 
statements.

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 
generator expressions).

> 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:
       if cond(i):

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):
      yield x

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
> condition?

'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.

Regards,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.blogspot.com


More information about the Python-Dev mailing list