[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