7 ms·
The optional “else” in Python loops
- Psyonic 12y agoWhile 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.)
- thatswrong0 12y agoI agree. I use it, but intuitively, I think of else acting the opposite way - if the loop finishes successfully, great! else, do something.
- eurleif 12y agoIf you're using break to signal success, that is how else acts.
- thatswrong0 12y agoI've been using break to signal failure. I'll keep that in mind.
- maxerickson 12y agoJust to illustrate: >>> for item in (1,2): print(item) else: print('Done!') 1 2 Done! >>> for item in (1,2): print(item) break else: print('Done!') 1 >>> edit: also: >>> for item in (): print(item) else: print('Done') Done
- deleted 12y ago[deleted]
- simonw 12y agoI 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.
- MBlume 12y agoWhat 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.
- BWStearns 12y agoThat logic definitely helps me think about it. But it does seem like a switch from the other wording that python uses. Feels like finally would be more intuitive, whereas without thinking about the search loop case else feels like something that would be triggered by a break or return. I wonder if using the feature would be more common if it was more intuitively worded.
- maxerickson 12y agoIt's analogous to the natural termination of a while-else, where the else block is executed after the condition evaluates to false: >>> a=1 >>> while a>0: print(4) a=a-1 else: print('done') 4 done clarity cribbed from here: https://mail.python.org/pipermail/python-list/1999-July/004457.html https://mail.python.org/pipermail/python-list/1999-July/0044...
- MBlume 12y agoOh, that helps too -- it's an else clause for the conditional of the while loop :D
- MBlume 12y agofinally seems much more confusing to me -- the point of finally is that it will definitely be executed...
- pyre 12y agoI think the real issue is that the word 'else' is ambiguous in the context. Everyone comes in with a different idea of what the 'else' is a fallback clause to. Guido obviously picked one particular case, but there are other valid meanings. For example, I think that it's more common to want to do something like: # mnemonic: # for thing in list_of_things DO_SOMETHING else DO_SOMETHING_ELSE if list_of_things: for thing in list_of_things: print thing else: print "No things!" Than: for thing in list_of_things: if thing.is_awesome: break else: print "No awesome things!" And what about conditional code that you want to execute when a loop does break early? error_found = False for thing in list_of_things: if thing.error_condition: error_found = True break if error_found: pass
- wting 12y agoRaymond Hettinger has suggested that instead of `else:` the keyword should have been called `nobreak:` which conveys intentions better.
- avn2109 12y agoWhat about using "finally," which if IIRC is already a thing in Python and encapsulates this idea pretty neatly?
- dbarlett 12y agofinally blocks are always executed; this kind of else block is only executed if the for block exited normally (i.e. did not throw an exception).
- BerislavLopac 12y agoOr "unbroken", even... ;-)
- enneff 12y agoI 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. :-/
- blahedo 12y agoWhat'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
- chrismorgan 12y agoThat last one is not idiomatic (I’ll ignore the lowercase first letter of True and False). The `else` there is superfluous; that cuts it down to this: def look_for_something(parameter): for item in list: if matches(item, parameter): return True return False And then after that one should just replace the entire loop with an `any` call: def look_for_something(parameter): return any(matches(item, parameter) for item in list) Also, if we assume a `matches()` that is simple equality, then it would just be def look_for_something(parameter): return parameter in list … and even then, you shouldn’t have named a variable `list`. Cut down to its essence like this, the function probably shouldn’t have even existed… ☺
- blahedo 12y agoRemember that I was talking about novice programmers, here. I'll concede that "idiomatic" was a bit strong (and the True/False thing was a brain fart), but I think my main point stands: encouraging the use of an "else:" that can attach to loops, with an unobvious and somewhat nuanced semantics, is not kind to newcomers. And the fact remains that the difference between a correct implementation and one that is wrong in exactly the way that a lot of newcomers get it wrong is nothing but indentation.
- agrover 12y agoRaymond Hettinger, one of the main Python devs, advises that the "else" in this situation should mentally be thought of as "notfound".
- eddyg 12y agoGlad you posted this. I came to the comments to post the same thing[1] because thinking of it as "notfound" makes remembering (and comprehending it) easier. :) [1] https://www.youtube.com/watch?v=OSGv2VnC0go#t=17m12s https://www.youtube.com/watch?v=OSGv2VnC0go#t=17m12s
- agrover 12y agoAh, I misremembered, "nobreak", not "notfound".
- a3n 12y agoI think "else" should be pronounced "then" for the for and while loops. And the meaning is "then and only then."
- kazinator 12y agoThis 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.
- gejjaxxita 12y agoI 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 12y agoThere 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.
- pyre 12y ago> There will always be non-expert programmers of many languages. Avoiding language-specific constructs will not solve the issue. This is a language-specific issue that occurs rarely in the wild. Yes, it's part of the language, but it's used rarely enough that it can trip up even experienced Python programmers. For example, Perl (until more recently) allowed one to change arrays to be 1-indexed, rather than 0-indexed at runtime. Just because it's part of the language doesn't mean that it's a good thing to use it.
- collyw 12y agoAs someone who did years of Perl (and that's not the most intuitive of languages), I was really confused when I first saw this in Python.
- est 12y ago> who encounters this will be confused And get it after 30 seconds doc reading?
- andrewchambers 12y agoIn my opinion it's just poorly named.
- 12y ago
- jw2013 12y agoThis is all in Jeff Knupp's Writing Idiomatic Python: http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-p... Many so-called Python Idioms are really non-intuitive and I don't really appreciate.
- abuddy 12y agoThey are intuitive and very easy to understand and read the code. If you use Python you should code in Python, not trying to translate C to Python.
- mdaniel 12y agoFor 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 12y agotry/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.
- gomesnayagam 12y agoit clear to me that this notion is not maintainable at all after looking the comments though it is nice feature to have.
- enesunal 12y agoI would choose `finally` keyword over the `else`.
- bashwork 12y agoCreated an account to point out this gem by Guido himself that makes use of this and the fact that python variables are not scoped inside for loops: https://github.com/aosabook/500lines/blob/master/crawler/crawling.py#L100 https://github.com/aosabook/500lines/blob/master/crawler/cra...
- ludwik 12y agoOh my God! I would be so confused reading this code!
- ddandd 12y agoNot 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.)
- mhd 12y agoAlso 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)
- parham 12y agoMight be worth while looking at the video below for more Pythonic gems like this one. https://www.youtube.com/watch?v=OSGv2VnC0go https://www.youtube.com/watch?v=OSGv2VnC0go