On Wed, 29 Jun 2016 08:01 pm, Victor Savu wrote: > There are many posts trying to explain the else after for or while. Here > is my take on it: > > There are three ways of getting out of a (for/while) loop: throw, break or > the iterator gets exhausted.
- reaching the end of the loop - raise (not throw) - return (if inside a function) - calling os.abort() - calling os._exit() - break So at least six ways. > The question is, how cab we tell which way we exited? I'm not really sure that is the right question to ask, but okay, let's continue and see where this goes. > For the throw, we have the except clause. Which `except` clause? `except` is not part of the for statement, it is completely independent. There may, or may not, be an `except` clause anywhere in your code. In either case, the `raise` behaves like a GOTO, jumping to the nearest `except` clause (if any). That may be inside the loop: for x in seq: try: do_something(x) except Error: ... or outside the loop: try: for x in seq: do_something(x) except Error: ... or there may be no except clause at all, and control is transferred to the top-level error handler (if any) or to the Python interpreter, which then prints a stack trace and exits. > This leaves us to > differentiatr between break and normal exhaustion of the iterator. Following `return`, the function returns and transfer returns to the caller's code. Following os.abort(), the interpreter exits in the hardest, quickest manner possible. Following os._exit(), the interpreter exits without doing any normal cleanup or processing. In those two cases, we cannot run any Python code after the function is called, so the question of distinguishing them from ending the loop normally doesn't come up. Nevertheless, they do exit the loop. > This is > that the else clause is for: we enter the body iff the loop iterator was > exhausted. The way I would put it is that we enter the body of the `else` statement when the loop reaches the end. That applies to both `while` and `for` loops, and it applies to looping over sequences using the sequence protocol instead of the iterator protocol. It applies to empty sequences (the loop reaches the end immediately). And it even applies to infinite loops: if the loop never ends, the `else` statement never runs. And most importantly, if we transfer control out of the `for` statement using *any* other mechanism (break, return, raise, os.abort, ...) then the `else` statement never runs because we have jumped past it. > I for one would have chosen 'then' as a keyword to mark > something that naturally happens as part of the for statement but after > the looping is over; I agree with this. > assuming break jumps out of the entire statement, it > makes sense that it skips the 'then' body as well. And this. > (In the same way, I > prefer 'catch' to 'except' as a correspondent to 'throw', There is no "throw" in Python, there is "raise". > but all of this > is just bikeshedding). At a language design level, the decision was made > to reuse one of the existing keywords and for better or worse, 'else' was > chosen, which can be thought of as having no relation to the other use of > the same keyword in the 'if' statement. The only rationale behind this was > to save one keyword. Agreed. -- Steven “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list