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.)
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.
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
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. :-/
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.
Glad 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. :)
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.)
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.
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
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)
[+] [-] Psyonic|11 years ago|reply
[+] [-] simonw|11 years ago|reply
[+] [-] wting|11 years ago|reply
[+] [-] thatswrong0|11 years ago|reply
[+] [-] blahedo|11 years ago|reply
[+] [-] enneff|11 years ago|reply
[+] [-] MBlume|11 years ago|reply
[+] [-] agrover|11 years ago|reply
[+] [-] a3n|11 years ago|reply
[+] [-] eddyg|11 years ago|reply
[1] https://www.youtube.com/watch?v=OSGv2VnC0go#t=17m12s
[+] [-] kazinator|11 years ago|reply
[+] [-] ddandd|11 years ago|reply
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
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
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
And get it after 30 seconds doc reading?
[+] [-] bashwork|11 years ago|reply
https://github.com/aosabook/500lines/blob/master/crawler/cra...
[+] [-] ludwik|11 years ago|reply
[+] [-] gomesnayagam|11 years ago|reply
[+] [-] mdaniel|11 years ago|reply
[+] [-] edavis|11 years ago|reply
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
[+] [-] parham|11 years ago|reply
https://www.youtube.com/watch?v=OSGv2VnC0go
[+] [-] jw2013|11 years ago|reply
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|11 years ago|reply
If you use Python you should code in Python, not trying to translate C to Python.
[+] [-] enesunal|11 years ago|reply