for / while else doesn't make sense

Steven D'Aprano steve at pearwood.info
Thu May 19 14:02:24 EDT 2016


On Fri, 20 May 2016 03:22 am, Ned Batchelder wrote:

> On Thursday, May 19, 2016 at 12:43:56 PM UTC-4, Herkermer Sherwood wrote:
>> Most keywords in Python make linguistic sense, but using "else" in for
>> and while structures is kludgy and misleading. I am under the assumption
>> that this was just utilizing an already existing keyword. Adding another
>> like "andthen" would not be good.
>> 
>> But there is already a reserved keyword that would work great here.
>> "finally". It is already a known keyword used in try blocks, but would
>> work perfectly here. Best of all, it would actually make sense.
>> 
>> Unfortunately, it wouldn't follow the semantics of
>> try/except/else/finally.
>> 
>> Is it better to follow the semantics used elsewhere in the language, or
>> have the language itself make sense semantically?
>> 
>> I think perhaps "finally" should be added to for and while to do the same
>> thing as "else". What do you think?
> 
> For/else has always caused people consternation.
> 
> My best stab at explaining it is this: the else clause is executed if no
> break was encountered in the body of the for loop.

You're describing the consequences of the break: it breaks out of the entire
for statement, which includes the (badly named) "else" clause.

It's also misleading: break is not the only way to skip the else clause. You
can also return, or raise.

As far as I can determine, if you consider all the corner cases, the best
description of the behaviour is:

- the "else" clause is UNCONDITIONALLY executed after the for-loop has
completed, but before any code past the for...else blocks gets to run.

- anything which breaks outside of the for...else will prevent execution of
the else clause. returns jumps all the way out of the function, break
doesn't jump out of the function but it jumps out of the combined
for...else block.



> A simple structure would look like this:
> 
>     for thing in container:
>         if something_about(thing):
>             # Found it!
>             do_something(thing)
>             break
>     else:
>         # Didn't find it..
>         no_such_thing()
> 
> I think of the "else" as being paired with the "if" inside the loop.

The fatal flaw with that is that there is no requirement that there be any
such "if" inside the loop. In fact, there's no need to even have a break in
the loop at all! 


> At run time, you execute a number of "if"s, one for each iteration 

"One"?

for x in sequence:
    if condition: break
    if x < 0: break
    if today is Tuesday: break
    if i.feel_like_it(): break
else:
    print("which `if` matches this `else`?")


> around the loop.  The "else" is what gets executed if none of the
> "if"s was true.  In that sense, it's exactly the right keyword to
> use.

So long as you don't think too hard about what's actually going on, and only
consider the most obvious case, it almost makes a bit of sense :-)

But really, the else clause *actually is* an unconditional block which
executes after the loop. That's how it is implemented, and that's how it is
best understood.




-- 
Steven




More information about the Python-list mailing list