4 ms·
No, an explicit break skips the else clause and the else clause is evaluated if and only if the iterator in the loop raises a StopIteration exception (i.e., it'
by gh02t 8y ago
No, an explicit break skips the else clause and the else clause is evaluated if and only if the iterator in the loop raises a StopIteration exception (i.e., it's exhausted). For example, this code will still evaluate the else clause even though the break statement is always true, because iter([]).next() throws StopIteration immediately:
for i in []:
if True: break
else: print("Foo")
while this will not:
for i in [1]
if True: break
else: print("Bar")
The "conditional" in a for loop is that the iterator (l in your example) raises a StopIteration exception. I don't really like calling it a conditional though, because it's actually handled as an exception. I guess you could think of the condition being "are there any items remaining in l? If 'no' then evaluate the else clause." I've always considered the else clause on a for loop's proper purpose being to catch erroneous cases, for instance if you try and loop over files in an empty directory. Or if you have no matches searching line by line over a file. Etc.
- noobermin 8y agoYou're right, technically, but the way tzs thinks about it can still be correct if one thinks about it this way: the if statement in your first loop is mathematically true, but it is never executed because [] is of course empty. It's not about whether the inner if ...: break statement's conditional can evaluate to true. A lazy way to think about it is that way, but as long as you remember that it's what occurs when there is no break it's fine.
- gh02t 8y agoMy point is mainly that it's determined by the loop iterator, not the body of the loop; the else clause being skipped if you explicitly break is a consequence of this, not a cause. This is important because there is another case that can terminate the loop early- the else will not be evaluated if the loop body throws an exception (even if it is caught): try: for i in range(5): raise Exception else: print("Foo") # still won't be evaluated except: print("Loop aborted") The vacuous case (iterating over []) is also kinda important if you're iterating over something of variable length in case you need to distinguish between "loop terminated normally" and "input was empty". "else" can't really tell these two cases apart.
- noobermin 8y agoThat's a very good point. I guess to me, I've already internalized the "else stands for when the loop doesn't terminate early ever" but for people new to the language or feature it might be confusing. The fuzzy reasoning above was my original way of having it make sense in my head but I've since internalized the logic of how it really works.
- gh02t 8y agoYeah the thing I see that sometimes confuses people is that they think "else" works kinda like "finally" or "__exit__" in a context manager, where it's guaranteed to be called even if an exception is raised. I don't think there's anything wrong with thinking about it like you say, just need to be aware of a few edge cases. Else in a for loop is kinda obscure anyway, so its importance is marginal. It is really handy for a couple specific patterns, but I've only ever found myself using it a handful of times (and I write a lot of Python).