The optional “else” in Python loops
shahriar.svbtle.com
shahriar.svbtle.com
>>> 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 >>> 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/0044...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 if blah:
for .. in ..:
..
else:
..
is visually confused with: for .. in ..:
..
else:
..
What I'm saying is that for-else and while-else add syntax to the language that only solves a single specific instance of a class of similar issues, making it confusing.Let's consider the issues that are in the same class:
- execute code block when loop condition isn't met the first time (i.e. loop never executes).
- execute code block when loop exits prematurely (e.g. break).
- execute code block when loop doesn't exit prematurely (e.g. no break) // execute code block when loop condition evals to false (first eval or any subsequent eval)
Only one of these issues is solved by the for-else/while-else syntax currently in Python, and using a generic keyword (else) just heightens the confusion (especially since this syntax differs from many other languages).
All of these cases may require the use of sentinels / additional checks to implement. Why is one specific instance any more relevant than the others to the point that it gets special treatment (i.e. special syntax in the core language)?
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 falseThe `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… ☺
(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.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.)
A language is meant to be read not just written. A non-expert python programmer who encounters this will be confused.
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.
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.
And get it after 30 seconds doc reading?
I encountered this situation. I assumed the else belonged to an if, but the indentation rules were somehow being broken. What would you expect me to look up in the docs?
https://github.com/aosabook/500lines/blob/master/crawler/cra...
try:
None.doit()
except Exception as e:
logger.exception('Nope')
else:
# now what?
passAll it means is the try clause didn't raise any exceptions. And a "finally" clause is ran whether an exception was raised or not.
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.
If you use Python you should code in Python, not trying to translate C to Python.