[Python-ideas] for/except/else syntax

Steven D'Aprano steve at pearwood.info
Fri Oct 9 04:08:02 CEST 2009


On Thu, 8 Oct 2009 07:52:04 pm Yuvgoog Greenle wrote:
> -1 on for...then
> Everything after the for loop is a "then":

What "everything after"? We're talking about a block construct. It's a 
self-contained syntactic unit: a for line, a code suite, an optional 
else line + another code suite. We're not talking about additional code 
(which may or may not exist) outside of the block. If I say:

for x in seq:
    pass
print "spam spam spam"

print is not part of the for block. It's an independent piece of code. 
You can move it somewhere else:

print "spam spam spam"
for x in seq:
    pass

and it's still legal. But you can't do the same with a for...else 
loop -- you can't move the "else" before the "for". They *have* to be 
executed in order: first the loop, THEN the else-suite. And break jumps 
to the end of the entire block: both the loop itself, and the 
else-suite. That's all it does.

> for i in SEQ:
>     A
> # then
> # code follows
>
> The special thing about "else" is that it's skipped upon break.
> That's the *one and only* use case.
>
> Since the current "else" clause only tests for "if not break",

You are incorrect. The else clause doesn't test *anything* -- it is an 
unconditional jump, to the end of the entire for-block. for...else is a 
*single* unit, as far as Python is concerned, it just happens that the 
else part is optional.


>>> import dis
>>> code = compile("""for x in seq:
...     break
... else:
...     print "no break"
... """, '', 'exec')
>>> dis.dis(code)
  1           0 SETUP_LOOP              20 (to 23)
              3 LOAD_NAME                0 (seq)
              6 GET_ITER
        >>    7 FOR_ITER                 7 (to 17)
             10 STORE_NAME               1 (x)

  2          13 BREAK_LOOP
             14 JUMP_ABSOLUTE            7
        >>   17 POP_BLOCK

  4          18 LOAD_CONST               0 ('no break')
             21 PRINT_ITEM
             22 PRINT_NEWLINE
        >>   23 LOAD_CONST               1 (None)
             26 RETURN_VALUE

You will notice SETUP_LOOP line. The end of the loop is the end of the 
else clause, not the end of the for clause.


> I 
> think spelling it out somehow could extremely improve "else"
> readability.

I've gradually come to agree that "else" is an unfortunate choice of 
word for this keyword. It's misleading because it sounds like it 
executes if the loop is empty, and that's not what it does.

But consider your proposal:

for x in seq:
    ...
else no break:
    ...

It's needlessly verbose -- three words instead of one. It's easy to get 
confused with variants like "else break" (execute only if you *did* 
break), "if no break", "elif no break", "else not break", etc. If the 
intention is to come up with wording that people will remember, this 
isn't it. And lastly, it implies the existence of some magical global 
variable "break" which doesn't exist, and people will wonder why they 
can't do this:

for x in seq:
    ...
do_something()
do_something_else()
# now check how we exited the for loop earlier
if break:
    print "found!"
else:  # or else no break:
    print "not found!"

I guarantee that if your proposal goes ahead, folks will ask why Python 
doesn't expose the "break" flag outside of the for loop. The real 
answer is that there is no such flag, but your suggestion makes it seem 
like there is.



-- 
Steven D'Aprano



More information about the Python-ideas mailing list