On Sunday 12 June 2016 17:01, pavlovevide...@gmail.com wrote: > On Thursday, May 19, 2016 at 9:43:56 AM UTC-7, Herkermer Sherwood wrote: >> Most keywords in Python make linguistic sense, but using "else" in for and >> while structures is kludgy and misleading. I am under the assumption that >> this was just utilizing an already existing keyword. Adding another like >> "andthen" would not be good. [...] >> I think perhaps "finally" should be added to for and while to do the same >> thing as "else". What do you think? > > I agree it's not the clearest name, but it does behave consistent with > if...else.
Er, not really. if condition: print "A" else: print "B" Exactly one of "A" or "B", but NEVER both, will be printed. for item in sequence: print "A" else: print "B" Normally we would expect that both "A" and "B" will be printed. There will be a variable number of "A"s printed, zero or more, and exactly one "B", but the point is that in general BOTH will run, which is the opposite of if...else. The actual semantics are: - run the for block - THEN unconditionally run the "else" block The only way to skip running the "else" block is to jump out of the entire for...else statement, using `return`, `raise` or `break`. > Here's how I make sense of for...else. Consider this loop: > > for item in seq: > if pred(item): > use(item) > break > else: > not_found() That's the major intended use of "else", but note that it is NOT paired with the `if`. You can have: def func(): for item in seq: if pred(item): use(item) if condition: return something else: different_use(item) continue do_more() break else: not_found() or any of an infinite number of other combinations. You can't really understand for...else correctly if you think of the "else" being partnered with an "if" inside the loop. What if there is no "if"? Or ten of them? Of if they all already have "else" clauses? > This particular loop functions as a kind of a dynamic if...elif...else > statement. You can see that if you unroll the loop: > > > if pred(seq[0]): > use(seq[0]) > elif pred(seq[1]): > use(seq[1]) > elif pred(seq[2]): > use(seq[2]) > else: > not_found() They are only equivalent because of the "break". Take the break out, unroll the loop, and what you have is: if pred(seq[0]): use(seq[0]) if pred(seq[1]): use(seq[1]) if pred(seq[2]): use(seq[2]) not_found() Put the break back in, and you have: if pred(seq[0]): use(seq[0]) GOTO foo # not actual Python syntax, but see below if pred(seq[1]): use(seq[1]) GOTO foo if pred(seq[2]): use(seq[2]) GOTO foo not_found() label: foo Admittedly GOTO isn't Python syntax, but this actually is the way that the bytecode is done: the else clause is executed unconditionally, and a break jumps past the else clause. In Python 3.3, "break" is compiled to a JUMP_ABSOLUTE bytecode. You can see this for yourself using the dis module, e.g.: import dis code = compile(""" for i in seq: this() if condition: break that() else: another() print("done") """, "", "exec") dis.dis(code) > You will note that the else block is the same in both the rolled and unrolled > versions, and has exactly the same meaning and usage. But not in the general case. Only certain specific uses of for...else behave as you suggest. > As for a more appropriate keyword, I don't like the examples I saw skimming > this thread; neither "finally" nor "then" communicates that the block would > executed conditionally. The block isn't executed conditionally. The block is executed UNCONDITIONALLY. The only way to avoid executing the "else" block is to jump past it, using a return, raise of break. > If you want my opinion, you might as well use something explicit and > unambiguous, like "if_exhausted", for the block; But that is exactly what the else clause is NOT. That is an incredibly common mistake that people make, thinking that the "else" clause executes when the sequence is exhausted. At first, it *seems* to be the case: py> seq = [] py> for item in seq: ... print("not empty!") ... else: ... print("empty") ... empty but that wrong. py> seq = [1, 2] py> for item in seq: ... print("not empty!") ... else: ... print("empty") ... not empty! not empty! empty py> print(seq) # not exhausted [1, 2] The else clause has nothing to do with whether or not the for block runs, or whether it is empty, or whether the iterable is exhausted after the loop is complete. The else clause simple runs directly after the for block, unless you skip it by using the Python equivalent of a GOTO. > If you really want my opinion, it probably shouldn't be in the language at > all, even though I happily use it from time to time, and my code is better > for it. o_O > But it's not useful enough that the language would really suffer > without it, and it would save some users from something that can be quite > confusing. As confusing as threads? As confusing as multiple inheritance? As confusing as asynchronous programming? If you have seen as many beginners ask "why do I always get 100 heads or 100 tails?" as I have: count_heads = 0 coin = random.choose(['heads', 'tails']) for i in range(100): if coin == 'heads': count_heads += 1 print("number of heads:", count_heads) print("number of tails:", 100 - count_heads) then you will understand that "confusing" is often a matter of experience and understanding. Once you have the correct understanding of "for...else", there is nothing confusing about it. -- Steve -- https://mail.python.org/mailman/listinfo/python-list