semicolon at end of python's statements

Steven D'Aprano steve at pearwood.info
Mon Sep 2 04:05:02 EDT 2013


On Sun, 01 Sep 2013 21:58:15 +0200, Antoon Pardon wrote:

> Op 31-08-13 02:09, Steven D'Aprano schreef:

>> Adding a fourth option:
>>
>> for spam in sequence if predicate(spam):
>>      process(spam)
>>
>> saves absolutely nothing except a line and an indent level, neither of
>> which are in short supply, and gains nothing in readability over Option
>> 1.
> 
> So what is the big difference between this situation and the following:
> 
> | else:
> |     if condition:
> |         whatever
> 
> which in python we can write:
> 
> | elif condition:
> |     whatever
> 
> 
> So either is seems this was a design mistake or a line and an indent
> level can be important enough to allow a combination of controls.


The difference is that elif is syntax for chaining potentially large 
numbers of else if clauses:

if a:
else:
    if b:
    else:
        if c:
        else:
            if d:
            else:

It's not uncommon to have, say, a dozen separate elif clauses. Put that 
inside a method inside a class and you've got an indent of 56 spaces 
inside the final else block. But that's not really the problem, the real 
problem is that repeated nesting like this obscures the fact that it is a 
chain of if...if...if...if and all the if's really should be at the same 
indentation level.

In contrast, you never need to write something like this:

for item in seq: if a: if b: if c: if d: ...

since that's better written as 

for item in seq: if a and b and c and d:

So a "filtered for" only includes a single if clause. Multiple if clauses 
don't match the "one line or two" scenario:

for item in seq: if cond: <block> elif predicate: <block> else: <block>

is not an option. With a single if, filtering the for loop, this is an 
option:

# with or without the first colon
for item in seq: if cond:  
    <block>

versus:

for item in seq:
    if cond:
        <block>

What's the benefit of the first version? It doesn't make it any more 
obvious that the for is being filtered. It doesn't keep a whole chain of 
if clauses together. It doesn't let you do anything that you haven't 
already done. It just saves an indent and a newline. The cost, on the 
other hand, includes the risk that people will try to do this:

for item in seq: if cond:
    do_this()
    do_that()
    else:
        do_something else()

which is clearly nonsense. Worse is this:

for item in seq: if cond:
    do_this()
    do_that()
else:
    do_something else()

which is still nonsense but won't raise SyntaxError.

It would be a Bad Thing if adding a legal else clause to a legal if 
clause caused a syntax error. But the only way to prevent that is to 
prohibit the for...if one line version in the first place.

*None* of these objections apply to the list comp version of for, where 
the "block" consists of a single statement before the "for". So despite a 
superficial (very superficial) similarity between

[expr for item in seq if filter]

and 

for item in seq if filter:
    expr


I believe that Python is right to allow the first and prohibit the second.



-- 
Steven



More information about the Python-list mailing list