top | item 8050818

The optional “else” in Python loops

67 points| s16h | 11 years ago |shahriar.svbtle.com

48 comments

order
[+] Psyonic|11 years ago|reply
While in theory this is useful, it's one of the least intuitive parts of python for me. I avoid them whenever possible because I feel "else" conveys the intent very poorly. (And I've been writing python for years.)
[+] simonw|11 years ago|reply
I agree. Intuitively, I would expect for item in list: .... else: ... to execute the "else" clause only if the list was empty and hence the for loop didn't iterate at all.
[+] wting|11 years ago|reply
Raymond Hettinger has suggested that instead of `else:` the keyword should have been called `nobreak:` which conveys intentions better.
[+] thatswrong0|11 years ago|reply
I agree. I use it, but intuitively, I think of else acting the opposite way - if the loop finishes successfully, great! else, do something.
[+] blahedo|11 years ago|reply
What's more, it dances very close to something that is a super-common error for novice programmers: the early return from a loop. I grade AP exams every year, and one of the hands-down most common conceptual mistakes I've seen (on problems where this is relevant) goes something like this:

    boolean lookForSomething(int parameter) {
      for (Item item: list) {
        if (item.matches(parameter))
          return true;
        else
          return false;
      }
    }
where a correct answer would omit the "else" and put the "return false;" outside the bracketed loop (or, keep a boolean variable updated and then return that after the loop is done. Let's translate that to python:

    def lookForSomething(parameter):
      for item in list:
        if matches(item, parameter):
          return true
        else:
          return false
As a conceptual matter, for a beginner who is still trying to nail down the whole notion of "can stop early when found, but have to scan the whole list if not found", it is just plain nasty that the following code is not only correct but idiomatic:

    def lookForSomething(parameter):
      for item in list:
        if matches(item, parameter):
          return true
      else:
        return false
[+] enneff|11 years ago|reply
I totally agree. I wrote Python code professionally for five years and am shocked to find I was wrong about this all this time. I must have introduced quite a few bugs. :-/
[+] MBlume|11 years ago|reply
What finally made it intuitive for me: assuming the loop contains an if condition: break, you can consider the else-clause to be the else of the if statement within the loop.
[+] agrover|11 years ago|reply
Raymond Hettinger, one of the main Python devs, advises that the "else" in this situation should mentally be thought of as "notfound".
[+] a3n|11 years ago|reply
I think "else" should be pronounced "then" for the for and while loops. And the meaning is "then and only then."
[+] kazinator|11 years ago|reply
This badly named else is reminiscent of the "result forms" in Lisp loops like `dolist`, `do` or `loop`.

    (loop for x below 10
                finally (princ "iterated over everything, ") (princ "indeed"))
But, of course, these Lisp loops have a result value, and the result forms are an "implicit progn" which produces that value.
[+] ddandd|11 years ago|reply
Not only it is not very intuitive, I also find it to hurt the linearity of code. The code which will be executed after the loop ends depends on how the loop ended. break statement is usually a glorified but mostly harmless go to, but I think Python's go to statement isn't so harmless as it adds complexity but doesn't have big benefits.

But, I do think that the else clause on try\except blocks is less harmful. It is less harmful because the control flow complexity of exceptions handling is already there on the catch clause, so while exceptions does add big control flow changes, the addition of the else clause causes a relative minor change on the linearity of code (as it is already broken by catch: clause.)

[+] gejjaxxita|11 years ago|reply
I always strongly discourage the use of things like this construct in any language.

A language is meant to be read not just written. A non-expert python programmer who encounters this will be confused.

[+] solox3|11 years ago|reply
There will always be non-expert programmers of many languages. Avoiding language-specific constructs will not solve the issue.

As far as portability is concerned (if you port software by hand a lot, for example), this is indeed an issue; but if you work with people who write python code, you might as well use everything in your toolbox.

[+] est|11 years ago|reply
> who encounters this will be confused

And get it after 30 seconds doc reading?

[+] gomesnayagam|11 years ago|reply
it clear to me that this notion is not maintainable at all after looking the comments though it is nice feature to have.
[+] mdaniel|11 years ago|reply
For me, the optional else on for loops isn't nearly as mentally destabilizing as the optional else on try-except blocks. An ex-employee used to love doing that:

    try:
        None.doit()
    except Exception as e:
        logger.exception('Nope')
    else:
        # now what?
        pass
[+] edavis|11 years ago|reply
try/except/else used to throw me, but I've grown to like the idiom.

All it means is the try clause didn't raise any exceptions. And a "finally" clause is ran whether an exception was raised or not.

[+] mhd|11 years ago|reply
Also known as "Dijkstra's loop" to give credit where credit is due. Only other language I know that has it though is Oberon (and that just introduced it in a pretty recent update)
[+] enesunal|11 years ago|reply
I would choose `finally` keyword over the `else`.