
On python-dev the subject of for/else statements came up, so I had to mention how "ambiguous" the syntax seems to me. By "ambiguous" I meant that it's not obvious what should happen in the for/else and while/else constructs (the except/else construct is readable and great imo btw). Even though it's documented, for me it's a bad construct because it can and will always be misinterpreted by a non-trivial amount of people seeing it for the first time. It's unreadable and confusing because the "else" isn't referring to the "for" it's in reference to the "break". The construct is only useful in loops with "break" statements, so in pseudo code or human the "else" would have probably been translated to "if didn't break". To make things worse, it's not that newcomers will say "hmm, what does this for/else thing do? lets look at the manual", they will mistakenly assume they understand what the construct means. For evidence, see the for/else construct in the django templating language where "else" means the loop didn't run. The django interpretation IMHO is much more natural because "else" AFAIK means "otherwise" meaning that statements inside an "else" block will never be executed if the statements in the previous block were. To summarize: whatever: A else: B looks like it means either A happened or B happened. In python for/while/else constructs, this doesn't hold. --yuv Original Thread: [Python-Dev] Announcing PEP 3136 ---------- Forwarded message ---------- From: Terry Reedy <tjreedy@udel.edu> Date: Thu, Oct 1, 2009 at 2:47 AM Subject: Re: [Python-Dev] Announcing PEP 3136 To: python-dev@python.org Yuvgoog Greenle wrote:
Properly understood, no ambiguity. while c: x() is equivalent to hypothetical label z: if c: x() goto: z So while c: x() else: y() is equivalent to label 1: if c: x() goto: 1 else" y() The else clause fires (once) if and when the if/while condition evaluates as false. Break and continue are restricted *unconditional* goto statements, and so *cannot* trigger an else clause. In for loops, the implied condition is 'there is another item in the collection represented by the iterable'. For any more, move to another list. Terry Jan Reedy _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/ubershmekel%40gmail.com

I wouldn't modify the way for/else behaves btw. I would either:1. rename the "else" to something else for "for" and "while" loops 2. remove the syntax altogether. 2to3 or 3to4 can do this by changing a boolean before the "break" statement for example. expectations of those unwilling to learn the language I can tell you I love python and of course many newcomers will/do too. I'm just noting that this might be a pimple worth popping. One more thing, I have to clear django's name as it doesn't have a for/else construct, it has a for/empty construct that was inspired by a popular for/else django template recipe entitled:
"for" template tag with support for "else" if array is empty
(thanks for pointing that out Karen) On Thu, Oct 1, 2009 at 4:35 AM, alex23 <wuwei23@gmail.com> wrote:

Why single out for/while and leave out try? It supports an else statement in a similar fashion. Honestly I think the syntax is fine as it is. Once I grasped what it did and why, I exploited it to great effect. The syntax may be unfamiliar to programmers coming from other languages, but so what? The same can be said of every language on the planet. (I felt like an idiot when I started to learn Haskell). FWIW, nothing in life is intuitive. Absolutely nothing. Everything has to be learned, even the simplest things. A baby has to learn how to nurse and many struggle with that unintuitive process as well. The concept of what is "intuitive" is entirely in the eye of the beholder and is effectively a non-concept. -1. On Wed, Sep 30, 2009 at 9:58 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
-- Gerald Britton

Yuvgoog Greenle writes:
If you prefer some existing keyword, -0.75, else -1. Note: As a native speaker, since "for ... else" isn't English, I would certainly look up the semantics before using the syntax. This is very probably true for Japanese as well, who are far better at (consciously) remembering English syntax than native speakers are. I don't know about other non-natives.
2. remove the syntax altogether.
-1. It's occasionally useful, and when it is, it's nice and concise.

On Thu, Oct 1, 2009 at 1:17 AM, Stephen J. Turnbull <stephen@xemacs.org> wrote:
As another native speaker, I do find it confusing on most for loops -- so I don't use it there. It does make sense on search loops. Normal loop, where it is misleading: for item in source: process(item) else: # yikes, I would wrongly expect this to mean empty. But search loop where it makes sense: for candidate in source: if test(candidate): choice=candidate break else: choice=default (That said, even then, I tend to set the default outside the loop construct, just to avoid the else confusion.) -jJ

Yuvgoog Greenle schrieb:
I agree that the "else" clause is somewhat unintuitive. However, it has its uses and can often replace more awkward constructs. As such, I would be -1 on removing it, and -3 on reusing the else clause for some other purpose.
The block in question is called "empty" in the Django template language, not "else". If you look at the discussion that led to its introduction, you can see confusion with Python's else cited, and the tag was named "default"/"empty" because of that: http://code.djangoproject.com/ticket/6398 One template language that uses "else" for this case is Jinja (which is similar in syntax to Django templates, maybe you confused them). However, I know that Armin does know how Python's for-else works :) It is simply not useful for a (template) language that has no "break", while a "default" clause is very convenient there. Georg

I must say that calling for ... else "somewhat unintuitive" is the understatement of the year. The analogy with if ... else leads further astray than Odysseus. The feature itself is not bad. It's just that it is misnamed. I did a quick poll at the office and at IRC, five people in total, with 2-8 years of Python experience. Two had never heard of the for..else -construct; one had heard that it exists and two know about it but have never used it. Three uninitiated, in other words. All three gave similar replies: if the loop is not executed or the variable is not iterable, then the else-branch is executed. Here are their reactions, when they learned how it really works: * "It should be called for..then" (or for..finally) * "WHAT. No f** way. Completely unintuitive" * "I'd hate whoever wrote that code" These people are actual Python developers, not some newbies. And I completely agree with them. I've only once seen for...else in the wild and never used it myself. To add further insult to the naming injury, the else branch suffers from the fact that 99.9% of the time, the for-loop contains an if: for x in xs: if cond(x): break # stuff else: # more stuff My code pattern matching algorithm reads that as an indentation error. An else matches if so many times more often that decoding for..else requires unnecessary effort. I don't want the feature to be removed or even renamed (at least before Python 4). But the feature *is* badly named and unintuitive. -- [ Antti Rasinen <*> ars@iki.fi ]

Thank god for empirical evidence and thanks Antti for the measurement. This construct should have been named "finally", "didnt_break" or "not break": while self.more_points_to_check(): if self.found_it(): # Found the desired point breaknot break: # Exhausted the search space :( On Thu, Oct 1, 2009 at 2:00 PM, Antti Rasinen <ars@iki.fi> wrote:

Yuvgoog Greenle wrote:
Thank god for empirical evidence and thanks Antti for the measurement.
The plural of anecdote is not data... Although it seems the "general loop" form in Python may need to be better taught to make these semantics easier to remember :P while loop_cond: # loop body else: # else clause can be translated almost exactly as: while 1: if loop_cond: # Loop body goes here else: # Else clause goes here break The for loop form is a natural extension of that (with the implicit loop condition being "while there is stuff left in the iterable"). I can understand people not knowing what the construct means the first time they see it. But the underlying mechanics really shouldn't be all that difficult to grasp. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 8 Oct 2009 12:10:00 am Gerald Britton wrote:
Are you sure? Under what conditions would the "finally" clause be bypassed?
Are you talking about the existing try...finally clause, or the hypothetical "let's rename for...else to for...finally" clause? If the second, then it would be bypassed under exactly the same conditions as the else in for...else is bypassed. E.g.: for x in [1, 2, 3]: raise Exception else: print "This is never printed" def test(): for x in [1, 2, 3]: return x else: print "This is never printed" Renaming 'for...else' to 'for...finally' doesn't turn it into a try block. The semantics remain the same. -- Steven D'Aprano

On 2 Oct 2009, at 03:35 , Greg Ewing wrote:
Then again, a try's finally isn't *always* executed. It's *almost always* executed, but if the runtime (or just the thread the block is in) crashes, is killed with kill -9 or the machine is shut down, it won't be. Interestingly, because sys.exit throws an exception instead of killing the runtime, the finally block does run if you call sys.exit in the try block (in Java, it doesn't)

That's what I was getting at. As long as Python doesn't crash or the process is not killed by some external force (e.g. power failure), the finally clause of a try/except/finally will always be executed. On Wed, Oct 7, 2009 at 10:18 AM, Masklinn <masklinn@masklinn.net> wrote:
-- Gerald Britton

Antti Rasinen writes:
never used it. Three uninitiated, in other words.
Well, of course it's unintuitive, then. In practical programming, "unintuitive" is synonymous with "I've never used it in a real program."<wink>
Here are their reactions, when they learned how it really works:
* "It should be called for..then" (or for..finally)
I don't know about the semantics I'd guess for "then", but I think I'd consider that synonymous with "finally". IMO it's non-starter anyway because it's not already a keyword; this pattern is a little too uncommon to justify a new keyword. "finally" is no good because in try blocks it means "no matter what, do this". Having slightly different semantics in try blocks and loops would be a real loser.
I guess. However, you're a native speaker of a natural language, so I bet you can deal with idioms that are *much* less intuitive than this one, if used in context. Probably even in English (which I guess is not your native language). I find the search idiom very natural, almost intuitive (even though I've never used it myself<wink>), now that I've seen it in Nick's post. Don't you?

2009/10/1 Antti Rasinen <ars@iki.fi>:
I agree. I use it from time to time and I used to have to look up the docs every time, because I couldn't remember wheteher the 'else:' clause meant 'if did break' or 'if didn't break'. I solved this problem by stopping thinking about it as while-else or for-else, but rather as break-else. -- Arnaud

There is consistency between the use of "else" in for, while and try: The "else" suite is executed when the for/while/try statement is exhausted -- that is, is not terminated abnormally with a break, return, exception, etc. Once I got it, I GOT IT! and have found it quite handy. I don't think we should talk about changing this syntax for for/while without including the try statement. I do believe, though, that the idea is a non-starter since it would break existing code. As for the "intuitive" argument, that's a red herring. One person's "intuitive" is another's "obscure." The word is overused and undefined in any objective, measurable sense. Steve Ballmer likes it since he thinks it gives him a leg up on the competition. That should be enough for us to eschew its use. On Thu, Oct 1, 2009 at 9:54 AM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
-- Gerald Britton

On Thu, Oct 1, 2009 at 4:00 AM, Antti Rasinen <ars@iki.fi> wrote:
I must say that calling for ... else "somewhat unintuitive" is the understatement of the year.
"The nipple is the only thing that's intuitive. Everything else is learned." -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Thu, Oct 01, 2009 at 07:47:37AM -0700, Guido van Rossum wrote:
"There is no intuitive interface, not even the nipple. It's all learned." http://www.greenend.org.uk/rjk/2002/08/nipple.html Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Oleg Broytman writes:
On Thu, Oct 01, 2009 at 07:47:37AM -0700, Guido van Rossum wrote:
"The nipple is the only thing that's intuitive. Everything else is learned."
"There is no intuitive interface, not even the nipple. It's all learned."
"Although that way may not be obvious at first unless you're Dutch."

Let me rephrase - for..else is a _misleading_ construct. It suggests one thing yet does another. This response is way too long, so here's a TOC: 1. The Question Challenge - A way to examine if "for..else" is just unintuitive or misleading. 2. What can be done about for...else. 3. Lets talk about "try/else" because a few people mentioned it as though it's somehow related to the discussion. ---------------- 1. The Question Challenge - A way to examine if "for..else" is just unintuitive or misleading. Antti's experiment got me asking, you can try this as well. Ask a person who knows python the following questions: Question #1: Do you know what happens when an "else" appears after a "for" loop? if they answer yes then say nevermind. otherwise: continue to question #2. Question #2: When would the code in the "else" block execute? If you don't know, it's ok to guess. If they answer "when a break didn't occur", I'm willing to give you, the asker, up to 100 lines of patch code in whatever python project you want.. If they answer "maybe when the for loop didn't run or was an empty list" then you don't owe me anything. ------------- 2. What can be done about for...else. 1. Not allowing a for loop that has no "break" to have an "else". Just like "else" isn't allowed when there isn't an "except" in the "try". There really is no excuse, justification or sense in a "for" loop that has no "break" yet has an "else". 2. Lets not talk about removing the "else" from for/while completely since it does have its fans and cute use cases. 3. Renaming this construct for py4k wouldn't be too crazy if you use the existing reserved words "not" and "break". Look at this code and please note that it doesn't need any comments to make it readable (as opposed to Nick's example, no offence): for item in list_of_stuff: if item.is_awesome(): break not break: print("nothing is awesome :(") And I can even think of a few use cases for having just "break:". This block would execute only upon "break" occurring. That way you could have loops like this: for item in list_of_stuff: if item.is_awesome(): break break: celebrate(list_of_stuff) -------------------------- 3. Lets talk about "try/else" because a few people mentioned it as though it's somehow related to the discussion. "try/else" now _that_ is a red herring. There is no "try/else". OTOH "except/else", as I said before, is a beautiful, pythonic, useful and cool construct. This is the evidence:

On Thu, Oct 1, 2009 at 8:11 PM, Yuvgoog Greenle <ubershmekel@gmail.com>wrote:
When I see for/else I think of the second case even though I know it's not that. I think that second pattern is very common. In fact, I wrote code today that used it and I had to store the list in a variable and wrap the for in an if to test whether it was empty. Arguably, either one of these is appropriate for the word "else". I'd rather something like: for x in y: stuff else if no_break: more stuff else if no_elements: more stuff OK. This is ugly, but it's clear which of these is which use case. Surely someone can make this better in time for Python 4. --- Bruce

Yuvgoog Greenle writes:
+1. File an RFE against PyLint for sure, and against Python too. That's a *great* idea! Bikeshedding follows.
Er, no. It's more important if what people "know" is wrong than if naive guesses are wrong.
I would fire a programmer who gave an answer.<0.5 wink> He might do the same in his own code or in a review of someone else's.
Nick's example is far more readable IMO. No offense. I can tell you why, too. In his example, the "else" is immediately preceded by the "if ... break" suite. Because "break" can only happen once in a loop, I read the else as the alternative to breaking out. Sloppy, yes, but since this is the common idiom using for-else, it works for me. :-) OTOH, "break" is an imperative; "not break" looks like a prohibition to me, not the target of a branch. You could use "for: ... if not break:" but that looks ugly to me, and worse requires several tokens of lookahead to disambiguate from an ordinary if block. I'll leave it up to GvR to decide whether for-else is "less Pythonic" than try-except-else.
You'd need multiple breaks for this to make sense. Else: for item in list_of_stuff: if item.is_awesome(): celebrate(list_of_stuff) break Some people think that having multiple breaks is bad style.

2009/10/2 Stephen J. Turnbull <stephen@xemacs.org>
Nonsense - there are several other ways to break out of a loop. Raising an exception or returning for example. Michael

2009/10/2 Yuvgoog Greenle <ubershmekel@gmail.com>
The point is that the exception may be handled at an outer level - so the loop is broken out of and control flow is handed to another part of the code. Code that *always* raises an exception to break the loop is not common or interesting, but code that does so under certain circumstances is not uncommon (raising an exception is one way to break out of nested loops - the other way is an early return...)
The return may be conditional in order to explicitly break out of the loop under certain circumstances. Michael -- http://www.ironpythoninaction.com/

2009/10/2 Yuvgoog Greenle <ubershmekel@gmail.com>
Hmm... on consideration, breaking out of a loop without a break (i.e. exception or return) wouldn't enter the else clause *anyway*, so there is still no need for the else clause. My apologies, I retract. :-) Michael

I can't imagine why I'm still commenting on this thread, since there is no chance that Python will remove the "else" from for/while or put conditions on it, but here is an example of a use that has no break statement: for i, j in enumerate(something): # suite i += 1 else: i = 0 # i == number of things processed The thing here is, "i" won't be set by the "for" statement if "something" is empty. OTOH, if "something" is non-empty, i >= 1 at the end of the for-loop. Using the "else" clause in this way ensure that "i" has the number of things processed at the end of the loop. To do this without the "else" I have to: i = 0 for i, j in enumerate(something): # suite i += 1 I can't imagine why I'm still commenting on this thread, since there is no chance that Python will remove the "else" from for/while or put conditions on it, but here is an example of a use that has no break statement: for i, j in enumerate(something): # suite i += 1 else: i = 0 # i == number of things processed Does it work? Sure! But it moves the setting of "i" outside the for-construct, which I personally dislike. On Fri, Oct 2, 2009 at 8:58 AM, Michael Foord <fuzzyman@gmail.com> wrote:
-- Gerald Britton

On Fri, Oct 02, 2009 at 09:46:38AM -0400, Gerald Britton wrote:
Wrong, 'i' will always be 0 whether 'something' is empty or not. Without a 'break', 'else' is always executed. Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Those who believe that the for/else construct is sufficiently clear, please read this email again: Gerald Britton:
I don't mean to pick on Gerald, but he got the meaning of for/else dead wrong *in the middle of a debate about for/else*. This shows that even experienced Pythoneers who read Python-ideas can be confused about the meaning of for/else. Using it in production code means leaving a trap for the programmers who come after you and read your code to get confused and create a bug. Yes, when the others turn your working use of for/else into a bug, it's their fault for not reading the tutorial more closely so as not get confused by it, but ultimately no matter how much you blame the user, that won't stop the next guy who uses your code from misunderstanding it. The best solution to this inherent confusingness is to leave bare for/else alone for the foreseeable future, but to add a less confusing synonym for this feature. I propose "else not break:" although "elif not break:" is good too. Rewriting Gerald's example as for i, j in enumerate(something): # suite i += 1 else if not break: i = 0 # i == number of things processed makes it 100% smack you in the face obvious that "Oh yeah, this is going to set i to 0 every time, since there's no break." In an unrelated but also good idea, it would be nice to be able to do what Gerald thought he was doing: for i, j in enumerate(something): # suite i += 1 else if None: #or some other suitable phrase for "empty" i = 0 # i == number of things processed — Carl

On Sat, 3 Oct 2009 11:18:44 am Carl Johnson wrote:
Damn straight it's their fault. I hope you're not suggesting that people shouldn't use any feature that might be misunderstood by lazy, ignorant or stupid developers?
You can already do this today, with no change to the compiler, using only a slightly different syntax to that suggested: for i, j in enumerate(something): # suite i += 1 else: # if not break i = 0 Best of all, it's an extensible syntax, so there's no need for bike-shedding arguments about whether it should be spelled "not break" or "no break" or "didn't break" or "only if loop ended normally". All of these variants, and more, are accepted: for i, j in enumerate(something): # suite i += 1 else: # no break occurred and so the loop ended normally i = 0 -- Steven D'Aprano

On Fri, Oct 2, 2009 at 9:18 PM, Carl Johnson < cmjohnson.mailinglist@gmail.com> wrote:
This seems to be an argument for better documenting this behavior, rather than an argument against the behavior per se.
To me its this is even less intuitive than the bare else- first you keep that, then you commandeer "if not break" to mean "if this didn't break". There may be a better syntax out there, but no offense, I don't see this as being it.
Again, not my cup of tea. Others will doubtless disagree. Geremy Condra

Sory Carl, I did NOT get it dead wrong. The else is executed if the for loop falls through. That's the whole idea. Probably I should have set i to -1 in the else clause of the toy example though: for i, j in enumerate(something): # do something i += 1 else: i = -1 if i > 0: # we did something If you don't think the else is executed when the for-loop falls through, then you should re-read the documentation, here: http://docs.python.org/reference/compound_stmts.html#the-for-statement Where it says (just as I did, but in other words): "When the items are exhausted (which is immediately when the sequence is empty), the suite in the else clause, if present, is executed, and the loop terminates." On Fri, Oct 2, 2009 at 9:18 PM, Carl Johnson <cmjohnson.mailinglist@gmail.com> wrote:
-- Gerald Britton

Gerald Britton wrote:
The code in your example is semantically identical to the following: for i, j in enumerate(something): # do something i += 1 i = -1 if i > 0: # This block is unreachable... Without a break statement in the body of the loop the else will by executed unconditionally, hence it is exactly the same as if the code it contains was just inline after the loop body. The semantics you describe can be obtained only by initialising i before the loop: i = -1 for i, j in enumerate(something): # do something i += 1 if i >= 0: # We did something Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Yes, quite right. Another way would be: for i, j in enumerate(x): # do something i += 1 else: if "i" not in vars(): i = 0 Is it better than initializing before? Not sure. I guess it's a matter of taste. On Sat, Oct 3, 2009 at 11:22 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- Gerald Britton

Gerald Britton schrieb:
And there is STILL no need for using an else clause here. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.

On 3 Oct 2009, at 13:49 , Gerald Britton wrote:
Thus, the following `if i > 0:` clause cannot under any circumstance be executed. Your code (unless there is a break in the 'do something' part) is equivalent to: for i, j in enumerate(something): # do something i += 1 i = -1 if i > 0: # can never happen

Yuvgoog Greenle writes:
I didn't say it was nonsense and I didn't mean it was nonsense. I can see no reason at all why PyLint wouldn't warn about "breakless for-else". "raise StopIteration" and "if __debug__: break" *may* be sufficient reason Python itself shouldn't be too noisy, but for sure PyLint should warn about it.

Stephen J. Turnbull wrote:
raise StopIteration in the body of the for loop will escape, just like any other suggestion. However, Gerald's point that the else clause can also be used to give the iteration variable a "default" value (with nary a break in sight) in addition to the more traditional search loop idiom is enough to convince me that the compiler should stay out of this one. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Michael Foord writes:
Sure. Maybe I'm missing something, but consider for x in xs: function_that_may_return_or_raise(x,xs) function_that_should_not_be_executed_in_exceptional_case(xs) Now, a return or raise cannot cause f_t_s_n_b_e_i_e_c to be executed; only a break can.[1] Only a break *needs* else. If you can give a stylistic rule to distinguish when that code should be spelled instead for x in xs: function_that_may_return_or_raise(x,xs) else: function_that_should_not_be_executed_in_exceptional_case(xs) then I agree. However, if you can't, I can't either, and I can offer no reason why we shouldn't warn about breakless for-else loops since they are very often not what the user wants, and if they are desired, they can be spelled equally well without else. Footnotes: [1] StopIteration can, but I thought raising StopIteration in user code is considered quite bad form.

StopIteration once put forward on this very list as a way to stop a generator. e.g. def stop(): raise StopIteration gen = (x in something if <x meets some condition> or stop() ) Toy example: Say you want the squares of all natural numbers n such that n <= j. Here's one simple way using the stop function above: from itertools import count squares = (n**2 for n in count() if n <= j or stop() ) Without the "or stop()" the generator goes into an infinite loop when n exceeds 10. Of course you can do this toy example other ways, this is just an illustration.
-- Gerald Britton

Yuvgoog Greenle wrote:
As Stephen said, that's a very good point. Having the compiler issue a SyntaxWarning when compiling such code is perfectly possible and would make a great deal of sense (and probably prevent many cases of naive misuse).
2. Lets not talk about removing the "else" from for/while completely since it does have its fans and cute use cases.
Good :)
If you want to turn the "else" into something explicit, the phrase you're looking for would be "elif not break". I think it's better just to teach people that's what the "else" means though - no need to make them type it every time. If you want to do things in the break case then that code goes inside the body of the loop (after checking the break condition, but before the break statement itself). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, 2 Oct 2009 09:01:20 pm Nick Coghlan wrote:
I disagree that it makes sense. Why raise a SyntaxWarning for legal code? Shall we raise SyntaxWarning for the following as well? #1 pass pass #2 if False: parrot() #3 for x in []: do_something() #4 try: something() except Exception: raise etc. There are all sorts of code which is legal but does nothing. Why should the language single out one of them for a warning? If that warning is anywhere, it should be in PyLint or equivalent. It's even more problematic when you consider code where the break is inside a "if __debug__" clause. Then you've code which raises a warning when you run with the -O flag, and doesn't when you run without. -- Steven D'Aprano

Nick Coghlan wrote:
After the additional posts in the discussion, I'm back to my previous opinion - the construct should be referred to as break/else (or for/break/else and while/break/else) and we should at least investigate having the compiler itself raise at least a SyntaxWarning if it encounters a for/else or while/else construct without also encountering a break statement inside the loop. The situation is *exactly* analagous to try/except/else: if there is no except clause, then using the "else" is redundant - just put the code inside the try block (if there is also a finally clause) or ditch the try statement altogether (if there is no finally clause). The compiler enforces this by treating try/else with no except clause as a SyntaxError. For a loop with no break statements the else clause will *always* be executed, hence using the clause is completely redundant - the code it contains might as well be dedented and placed inline at the same level as the loop header. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Sat, 3 Oct 2009 03:08:49 pm Nick Coghlan wrote:
Modulo returns and exceptions.
hence using the clause is completely redundant
True. But there is an effectively infinite amount of completely redundant code possible in Python. The performance hit and maintenance burden of raising warnings for redundant code would be immense, to say nothing of the nuisance value for the developer. Such warnings don't belong in the language, they belong in PyLint or equivalent.
True, except that the else clause clearly flags it as part of the semantic unit together with the for loop. Dedenting the code flags it as separate from the for loop. Apart from free style comments, we don't have a way of flagging code blobs finer than the function -- Python doesn't work that way. For instance, we're reduced to marking logical groups of code smaller than a function with comments. # Initialise the values. x = 2 y = 3 + x z = x*y + 1 # Process the sequence. value = 0 for o in seq: value = o - value + z value = 1.0/value # Do something else with it. value = parrot(value) return cheeseshop(value) It would be interesting to hypothesise about languages that naturally grouped (e.g.) the for loop and its pre-entry and post-exit code together into one obvious code unit. Python isn't that language, but (by accident, I'm sure) the else clause comes close. -- Steven D'Aprano

Ron Adam wrote:
As I've said elsewhere in this thread, while the else clause won't be executed in those cases, neither will any code that occurs immediately after the loop statement. Accordingly, using the else clause is unnecessary and rather misleading - just writing the extra code after the loop would be much clearer. The number one thing I have learned from this thread is the fact that the else clause only makes sense when used in conjunction with a break statement and the fact that this construct isn't regularly documented and explained as for/break/else and while/break/else is the major barrier to understanding what it does. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Document it as much as you want but the "else" doesn't hint or clue as to whether it catches breaks or is skipped by them. The next problem's gonna be at midnight when you're reading code and asking yourself "hmmm, for, blah blah, else, hmm oh yeah, else-break, so this else occurs whenever there's a break." On Sat, Oct 3, 2009 at 6:27 PM, Ron Adam <rrr@ronadam.com> wrote:

Yuvgoog Greenle wrote:
True, and that is part of the other 20% I expect the documentation would't help. The only solution to that that I can think of is to change the esle's in for and while loops to for/then and while/then in Python 5.0. It might be doable, and if enough people want it, then just maybe...

On Sat, Oct 3, 2009 at 7:19 PM, Ron Adam <rrr@ronadam.com> wrote:
Documenting this syntax with the appropriate warnings and clear explanations is very important. But I don't think the amount of code mishaps on this thread are properly addressed just by better documentation. The syntax I proposed is harmless, it won't break any existing code, and it's something people in python 3 can use right now. Deprecation etc can wait for python 4. Don't tea5e me :) Of course people here would have to say if my idea sounds good or not. while still_more_items(): if found_it(): break if not break: # exhausted search space

Yuvgoog Greenle wrote:
Lol, Sorry about that. ;-), but I do think it's too late to change for/else and while/else to for/then and while/then in python 4.0 already.
I suppose most people won't like the way break is used in two entirely different ways depending on where it is. When you see a break, two things become really clear: 1: you are inside a loop 2: we are exiting a loop When you use it in the other context it makes those things a bit less obvious especially if you consider loops inside of loops. We then have to consider the closeness these too statements are to each other. if not condition: break if not break: condition we aren't exiting a loop in the second case, even though it may be inside another loop. Cheers, Ron

You do have a point and I'll meditate on it. But I do think the situation is better than you made it appear. There will usually be a linebreak. We can't help the readability of code written by people that compress code. So a more fair representation would be: if not condition: break if not break: condition (note: I'm not sure what you meant by "if not break: condition") The bad case is when you have nested loops so it would look like this... for item in list_of_items: while condition: if reason_to_stop(): break if break: # do something after the while broke if other_condition: break On Sat, Oct 3, 2009 at 7:51 PM, Ron Adam <rrr@ronadam.com> wrote:

Looking over this all again, it seems to me that the main request would be for a more explicit statement in the documentation. Something like: "When the items are exhausted (which is immediately when the sequence is empty), the suite in the else clause, if present, is executed, and the loop terminates. Note: The suite in the else clause will be executed unless the iteration is terminated with a break or return, or raises an exception that is not handled or does not return." Probably it could use some word-smithing, but is that the basic idea? One thing I DO like about the construct, though, is it makes it more apparent what code belongs together. e.g. for x in y: # suite 1 else: # suite 2 It should be obvious that suite 2 belongs with the for statement in some way. OTOH: for x in y: # suite 1 # suite 2 You can't immediately see that suite 2 is related to the for statement. You might think it is completely independent which could lead to erroneous results if you modified it without keeping the for-loop context in mind. On Sat, Oct 3, 2009 at 1:13 PM, Masklinn <masklinn@masklinn.net> wrote:
-- Gerald Britton

Masklinn wrote:
I didn't say the behavior would change. for val in vals: if cond(val): break # processing val then: #all values processed # do more stuff The break would brake out of the entire for/then block. for val in vals: if found(val): searchval = val break then: # if not found searchval = default # breaks jumps to here I think that reads very well. :-) On the other hand "else" with the same comments really isn't all that much worse once you understand how break works in for/while loops. It's just a bit more of a hurdle for people new to python to get because of it's counter intuitive behavior compared else's use in if/else blocks. In those other languages that use case blocks, break is used to escape out of the entire case block in the same way break escapes out of the entire for/else blocks in python. Cheers, Ron

On Fri, Oct 2, 2009 at 5:35 PM, Steven D'Aprano <steve@pearwood.info> wrote:
All of your examples do exactly what they appear to do. The for...else construct that has no "break" appears to do something, yet does nothing. I beg of you to try out "The Question Challenge" I posted earlier. It's a win-win situation for you. If you're still not convinced, check out this code that is legal, yet appears to do something that it doesn't: try: z = math.sqrt(x / y) except ZeroDivisionError, ValueError: print("Math error, try again") That's a real life mistake many have seen occur. Python 3 fixed this in a very elegant way. Now let's talk python 4.

On Sat, 3 Oct 2009 01:42:48 am Yuvgoog Greenle wrote:
And so does for..else with no break.
The for...else construct that has no "break" appears to do something, yet does nothing.
Nonsense.
I beg of you to try out "The Question Challenge" I posted earlier. It's a win-win situation for you.
Your second question: [quote] Question #2: When would the code in the "else" block execute? If you don't know, it's ok to guess. [...] If they answer "maybe when the for loop didn't run or was an empty list" then you don't owe me anything. [end quote] But the else clause *does* run when the loop didn't run or was an empty list. That second answer would be correct, as far as it goes. It fails to describe all the behaviour of the else clause, but it's not wrong, merely incomplete.
Irrelevant. We're not talking about the syntax of the except statement. Why would confusing syntax there convince me that a *completely different* statement was also confusing? That's like saying, "If you don't agree that chocolate tastes terrible, have a taste of this cow-vomit. Terrible, right? So now we agree, chocolate tastes terrible." -- Steven D'Aprano

*snip* *snip* On Fri, Oct 2, 2009 at 6:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
*snip* *snip* On Fri, Oct 2, 2009 at 6:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
You present 2 claims so I present 2 answers, please don't mix the two up: 1. Does "for...else" do what it appears to be doing? 2. Does python allow syntax that's likely to cause confusion or mistakes? A summary of the long answers that follow: 1. In certain cases, no it doesn't. In a few cases showcased here - comments are the only way to make the code readable. 2. Python doesn't impose silly syntax limitations, but it can and has deprecated a "legal" syntax if a more readable, not misleading, alternative can be found/created/used. ---------------- 1. Does "for...else" do what it appears to be doing? This is subjective matter so of course we can agree to disagree. Let me entertain you Steven. First of all I suggest reading through this thread and looking for code examples with for..else that were refuted, retracted, misunderstood or wrong. I can count at least 3-4 instances from here (Carl noted Gerald's but there were others as well). This isn't python-noobs either, it's python-ideas. These are good pythonistas that were mislead by the for..else syntax. Secondly, I recommend anybody interested to go ahead and try "The Question Challenge". I'll rephrase it a bit to accommodate Steven's claims. Ask a person who knows python the following questions: Question #1: Do you know what happens when an "else" appears after a "for" loop? if they answer yes then say never mind. otherwise: continue to question #2. Question #2: When does the code in the "else" block execute? Of course you don't know so it's ok to guess. If they answer "when a break didn't occur", I'm willing to give you, the asker, up to 100 lines of patch code in whatever python project you want. If they answer "only when the for loop didn't run or was an empty list" then you don't owe me anything. To remove any doubt you can ask the follow up question "So either the for loop block runs or the else block runs, but in no way both?" If you want to have some good conversation, tell them what python really does with that "else". Please don't misinterpret this Question Challenge as an attack on Python. I love Python and I have no other language. At least no other language I enjoy using :) ---------------- 2. Does python allow syntax that's likely to cause confusion or mistakes? Short answer - preferably no. It's an issue of practicality vs purity etc. Also, python tries not to have silly limitations.
It would be a silly limitation to not allow: pass pass It would be a silly limitation because there's nothing wrong with "pass-pass". Concerning our specific discussion - "pass-pass" isn't likely to cause any confusion or mistakes. So what's a "syntax that's likely to cause confusion or mistakes"? For example, the old python 2 exception instance catcher: try: # code except Exception, e: # code Sounds ok, but now check out: try: # code except ExceptionClassA, ExceptionClassB: # handle errors of both exception types That usage of the syntax is wrong because ExceptionClassB wouldn't be caught and the exception instance would be named ExceptionClassB. This appears to do one thing (catch A and catch B), yet does something completely different (catch only A as B). Python 3 FTFY with "as". So the same code in the new syntax would be: try: # code except ExceptionClassA as ExceptionClassB: # handle errors of both exception types. The fact that ExceptionClassB is an instance is much more obvious and making mistakes is harder. So yeah, python tries to avoid syntax that may cause mistakes, in other words, the python syntax strives to be as expressive as reasonably possible. Note a few things please: 1. The python 2 syntax was legal 2. For python 3 it was declared an illegal syntax. 3. It was very easy to learn the correct python 2 syntax and not make mistakes but still it was fixed for py3k. 4. Doing crazy things that made no sense became a lot harder. I know I'm happy for that. I hope it's clearer how this example is relevant to "for..else" now. The point is if the "except" syntax can change from 2to3 to make it more readable and exact, so can the for..else syntax change from 3to4. Changing for..else would be done for very similar reasons. And don't get me wrong, I like nipples, chocolate and cow vomit as much as the next guy. It's just I would really love to discuss if and/or how this problem can be resolved.

On 2 Oct 2009, at 20:43, Yuvgoog Greenle wrote:
And then ask those same people if they know what a "data descriptor" is. There's some features of a language you just have to learn. And frankly, the for/else statement is very simple. It's surprising the first time you see it, but that's because few other languages have it. But, once you learn it, it's VERY handy. On 2 Oct 2009, at 22:08, Nick Coghlan wrote:
I would disagree. Imagine, while trying to debug code, you comment out an if statement inside the for loop, and now suddenly the whole loop becomes syntactically invalid. Plus, it's not only a break that could potentially make a for/else a valid construct. Return and yield are both legitimate, and technically anything that can throw an exception is too. Trying to implement the lexer to scan for all the possible combinations does not seem to be worth the effort. Jared

On 3 Oct 2009, at 08:15 , Jared Grubb wrote:
I'm sure that's why Nick suggests a Warning, not an Error. There's no reason to make a break-less (loop) else invalid, but there are plenty of reasons to warn the programmer of such a pattern, as it's usually either pointless or erroneous.
Return and yield are both legitimate, and technically anything that can throw an exception is too.
Yes, but these are irrelevant to the for:else: or while:else: cases.

It just hit me. The for...else is so cryptic because of one big issue - the "else". Consider the following code: for obj in iterable: if found_it(obj): # Found what we were looking for! break if not break: # It wasn't there :( Similarly for while loops: while self.more_points_to_check(): if self.found_it(): # Found the desired point break if not break: # Exhausted the search space :( Notice how readable and beautiful the code has become. We have 2 implementation options: 1. an "if" that comes immediately after a for/while can have the special keywords "not" or "break". 2. the for/while syntax has an optional "if break" or "if not break". I'd like to hear if people like this idea and if so, which of the 2 options do you like better. Check it out, there's no need for a syntax error because it's so obviously wrong: for item in list_of_items: process(item) if not break: do_something() Also, now that the syntax is generic, you can add on to it whatever you like. For example: for item in list_of_items: process(item) if item.is_gold(): break if item.is_silver(): break if break and searching_for_metals: celebrate(list_of_items) --yuv

Yuvgoog Greenle wrote:
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
The compiler can't handle it - it will see the "if" as the start of a new statement. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Ok, in theory, it's possible to flag a boolean after a for/while when compiling, but I think the "special syntax" option might be simpler to implement. So let's talk grammar... The old grammar was: while_stmt ::= "while" expression ":" suite ["else" ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite] And the new one I propose looks like this: while_stmt ::= "while" expression ":" suite ["if" expression ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["if" expression ":" suite] The "if" expression would be evaluated regularly but would have a magic boolean "break" that exists only in the if statement's expression eval. Note a few things: 1. the "if" would have been evaluated either way after the loop (exceptions/returns aside). 2. the only thing that's changed is the existence of the magic boolean "break". 3. You don't have to use it as the old "for...else" but you can and it's perfectly readable. I'm no expert on the compiler, but I have a strong feeling this is doable. On Sat, Oct 3, 2009 at 6:04 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:

Yuvgoog Greenle schrieb:
Sure, almost any language change is doable if you bend over backwards far enough and break all rules of consistency. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.

Yuvgoog Greenle wrote:
It means having to several tokens ahead before being able to tell whether you're continuing the current structure or starting another. Perhaps 'elif' instead? while still_more_items(): if found_it(): break elif not break: # exhausted search space If the body of loop wasn't executed at all: while still_more_items(): if found_it(): break elif pass: # empty search space

Since we're voting, Yuvgoog Greenle writes:
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
-1 on both. In one liners (ie, comprehensions and generator expressions) I think "for ... if" is readable, but it means something else!
Also, now that the syntax is generic, you can add on to it whatever you like.
With the wind chill factor, -2. The only other syntax I've seen so far that makes any sense to me at all is for x in xs: # suite containing break then: # suite to execute after processing all xs but that would require a new keyword, so that's -1, too.

On Sat, 3 Oct 2009 11:30:55 pm Yuvgoog Greenle wrote:
No I don't. It looks like you're testing against a boolean flag called "break".
Or #3: don't change a thing.
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
No. Neither of them.
Check it out, there's no need for a syntax error
That's right.
because it's so obviously wrong:
Your reasoning is backwards. If it were obviously wrong, there *would* be need to have a syntax error:
Syntax errors are for code which can't be compiled, not for code that does something unexpected, or unintuitive, or pointless. -- Steven D'Aprano

Jared Grubb wrote:
Return and yield are both legitimate, and technically anything that can throw an exception is too.
Nope, break is unique in that it will execute the code immediately after the loop while not executing the code in the body of the else clause. "yield" and "continue" won't terminate the loop at all, while "return" and a raised exception will skip all of the code after the loop whether it is in an else clause or not. The *only* way to skip the else clause without also skipping the code immediately following the loop is to use a break statement. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Yuvgoog Greenle wrote:
There is no "try/else". OTOH "except/else", as I said before, is a beautiful, pythonic, useful and cool construct.
This is also a very good point, but perhaps not quite in the way you intended (and it relates back to your first point about the compiler not complaining about redundant else clauses on loops that contain no break statements). Just as there is no "try/else", but only "except/else", so there is no "for/else" or "while/else", but only "break/else". Issuing a SyntaxWarning might be a good way to make that clear. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, 2 Oct 2009 09:06:11 pm Nick Coghlan wrote:
Just as there is no "try/else",
Perhaps there should be. Does anyone know why there isn't? It seems an arbitrary restriction to me, because the following pieces of code are not equivalent: # not currently legal try: if cond: raise ValueError else: print "no exception was raised" finally: print "done" versus: try: if cond: raise ValueError finally: print "done" print "no exception was raised"
but only "except/else", so there is no "for/else" or "while/else", but only "break/else".
That's certainly not true.
Issuing a SyntaxWarning might be a good way to make that clear.
Such a warning would be spurious. -- Steven D'Aprano

Steven D'Aprano wrote:
Just drop the else line and you get the semantics you're after: try: if cond: raise ValueError print "no exception was raised" finally: print "done" The reason except/else is necessary is that the code in the else clause runs: 1. Outside the scope of the exception handler 2. Only if the except clause isn't taken If there is no except clause, then the code that would have been in the else clause can just be moved to the end of the try block (as in the example above). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, Oct 2, 2009 at 6:34 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Also, in English/programmer/pesudo-code/human language, the following: something: A else: B Conveys that either A occurred or B occurred. This is just something everybody is used to because everybody knows if/else. Consider the following code: except: print("A brave attempt") else: print("Yippee") It's easy to understand that either "except" occurred or "else" occurred. The only time this rule is broken in python is the for/else and while/else.

On Sat, 3 Oct 2009 01:34:34 am Nick Coghlan wrote:
It's quite surprising to me that the following two pieces of code are equivalent: try: print "Catch exceptions here" except AttributeError: # Keep the compiler happy, raise # avoid SyntaxError. else: print "Don't catch exceptions here." finally: print "Done" and: try: print "Catch exceptions here" print "Don't catch exceptions here." finally: print "Done" I've spent some time playing around with various cases, and I can't find any example where they behaviour differently, but I am still not convinced that there's not some unusual corner case where they differ. -- Steven D'Aprano

2009/10/2 Arnaud Delobelle <arnodel@googlemail.com>
But as always with Python, the code in the else clause is not protected by the except so that you do not incorrectly handle unexpected exceptions. Michael

On Fri, 2 Oct 2009 17:12:25 +0100 Michael Foord <fuzzyman@gmail.com> wrote:
Um, there's not an except clause to protect anything there. In both cases, the code flows from the try: block to the else: block (even without the else: line) and then the finally: block, with an exception in the try: or else: block skipping the rest of both. Consider the three cases: 1) no exception raised - both cases print "no exception was raised" and "done". 2) exception in original try block - both cases just print "done". 3) exception in original else - both cases print whatever prints from the else block before the exception, and then "done". So the else: might as well be a pass. <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Steven D'Aprano wrote:
According to the Language Reference, the finally clause protects all of the preceding clauses in the try statement, including the else clause. So this would be equivalent to try: if cond: raise ValueError print "no exception was raised" finally: print "done" -- Greg

On Thu, Oct 1, 2009 at 11:11 PM, Yuvgoog Greenle <ubershmekel@gmail.com>wrote:
Head on over to graphine.org- I'm getting requests for database-backed graphs and don't know enough to do it portably. I asked 4 and got 2 correct answers, but I'm happy with the promised 100 lines. If you know as little about databases as I do, take a look at the graphml code- it's out of date and probably doesn't work. Geremy Condra

On Fri, Oct 2, 2009 at 7:07 PM, geremy condra <debatem1@gmail.com> wrote:
I'm on it. I don't know much about databases, django spoiled me, but I'll try. Others don't be discouraged, go for the challenge, I'll just stack and schedule your assignments if there are any more crazy hacks that can guess this one. I'm keeping score here, and yes, I know blind faith in strangers is blind, but it's worth it if the point'll come through in the end :-) --yuv

On Thu, 1 Oct 2009 09:00:21 pm Antti Rasinen wrote:
To add further insult to the naming injury, the else branch suffers from the fact that 99.9% of the time, the for-loop contains an if:
Really? You've done a statistically significant survey of code in the wild and come to a figure accurate to one part in a thousand? Not just plucked a number straight out of thin air? In my code, the figure is more like 20-40%. Choosing one representative module at random, only one in three for-loops include an if inside the loop. And when I use for...else, it's closer to 10%.
But then there are these: for x in xs: if cond(x): process() else: process_differently() else: do_something_else() for x in xs: process() else: do_something_else() They don't look anything like an indentation error to me. -- Steven D'Aprano

Steven D'Aprano wrote:
Am I missing something? Since those examples don't have any break statements in them, why do you use an else:? -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco

On Fri, 2 Oct 2009 01:23:27 pm Robert Kern wrote:
My bad -- process and process_differently are meant to stand in for a *block*, presumably including a break, not just a function call. I was attempting to show the indent structure. I shouldn't have included the parentheses, which just muddied the water. -- Steven D'Aprano

On 2009-10-02, at 06:07, Steven D'Aprano wrote:
Oh silly me. I used some sloppy language there. I did not mean that all for-loops have ifs inside them. What does your last statistic mean? Do you have if statements in only 10% of your for..else loops or in 10% of your all for-loops (including for...else)? If you mean the first case, then please ignore the rest of this message and post an example :-) What I meant that most *for...else* structures have an if inside. The 99.9% number is, as you say, plucked from thin air -- but I think it is very close to the truth. There are simpler alternatives to for..else if the loop does not contain an if. Consider the following structure: for x in xs: # body else: # else-branch If you don't have a break in the body of the for-loop, then you don't need the else: at all. You can write the above segment as: for x in xs: # body # else-branch If, on the other hand, you do have a break in the body, then either it is conditional or it is not. If there is no break, then you are either only processing the first element in the iterable or skipping directly to the else branch. In this case it would be natural to use plain if: if xs: # body with xs[0] # else-branch Iterators complicate the matter, but even in that case then I'd rather use a peeking wrapper around xs. It seems to me that the only sensible use case for for..else is when there is an conditional break inside the loop. I'll appreciate any counter examples, of course. Nick Coghlan's had a lovely example about search loops earlier in the thread. It also highlights one of the reasons why I think the for..else construct is so rare. Consider his example: for obj in iterable: if found_it(obj): # Found what we were looking for! break else: # It wasn't there :( There are several ways of writing this without for..else. If the context for the loop is correct, you might just use return True (or obj) during the loop. No need for an else-branch there. Or you might use any: if not any(found_it(obj) for obj in iterable): # It wasn't there :( It seems to me that there often are "more intuitive" ways of writing a for..else-loop. And accordingly, the construct is rare. I'll resort to some newspeak here and define "intuitive" as either "conveys the intent of the programmer better" or as "feels like the more obvious way to do it". Pick either. --Antti -- [ ars@iki.fi <*> Antti Rasinen ] This drone-vessel speaks with the voice and authority of the Ur-Quan.

I also find for:… else: unintuitive. I know if has something to do with break, but I always forget if it means "there was no break" or "there was a break." I support the following change: for item in items: suite else: #Same as before, executes only if there was no break for item in items: suite else not break: #Executes only if there was no break. #PEP-8 should deprecate the bare else in favor of this. for item in items: suite else break: #Executes only if there was a break for item in items: suite else None: #None is a keyword now, so why not? #Executes only if there were no items or in while-loops the condition is never true I think the latter two language changes would be welcome additions to Python regardless of whether for-else stays the same in the ordinary case of not. Yes, there are ways of telling if the loop never broke or never ran the suite besides adding these grammar changes, but so what? This a fairly common pattern, and I think it would improve readability without hampering the programmer's mental model of Python any more than the existing for-else does today. If anything, this would hamper the mental model *less*. Two-cents-ly-yours, —Carl M. Johnson

Antti Rasinen wrote:
Nope, as far as I know, that's what the construct is for - search loops.
I'd agree. However, given that it is an existing construct with valid (albeit fairly uncommon) use cases, I don't see much point in messing with it. Encouraging people to refer to the idiom as "break/else" and including a SyntaxWarning for dubious usage of loop else clauses (i.e. those without an associated break statement) are probably two fairly low cost educational steps that could be taken though. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, Oct 2, 2009 at 2:14 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
A SyntaxError would be more fitting for py4k but it's still not gonna make the for..else code readable. Asking people to call this construct a "break/else" is confusing because: 1. "break/else" insinuates the "else" block is for when a break statement _did_ occur. 2. the "else" is located immediately after the "for" block. Calling this anything but "for..else" is going to cause a tongue-twisting, mind boggling Stroop effect. IMHO the only way to avoid this is to rename/modify "else" to somehow convey it's relation to the break statement.

Yuvgoog Greenle wrote:
You need a much better reason than "it might confuse newbies" to justify breaking working code. In the primary intended context (search loops) the current terminology makes perfect sense: for obj in iterable: if found_it(obj): # Found what we were looking for! break else: # It wasn't there :( Similarly for while loops: while self.more_points_to_check(): if self.found_it(): # Found the desired point break else: # Exhausted the search space :( And once people learn the idiom, it is easy to remember (so long as they learn it properly - i.e. as an easy way to write a search loop with a separate handler for the "not found" case). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 1 Oct 2009 11:07:19 am Yuvgoog Greenle wrote:
That's a very fine distinction you are drawing, and I don't think it is useful. The else block runs when you exit the for-loop normally, by falling off the end. There are three ways to exit the for-loop without falling off the end: break, raise and return. raise and return are special: return exits the function immediately, nothing further gets run, and uncaught exceptions do similar. So the only way to exit a for-loop abnormally and still keep processing is with break. Hence you argue that the else refers to the break. But of course you can't have a break outside of a for loop, so else is equally associated with for. And in fact, it is legal to have for loops without a break but include an else. Is it useful? I don't know, but Python can't forbid them without breaking (pun not intended) code like this: for x in xs: if __debug__: break else: print "whatever" "if __debug__: suite" is special: the Python compiler optimizes the entire suite away when running with the -O flag. So if Python would treat the presence of an else as an error unless there was a break, you could have some code which was, or wasn't, legal according to the presence of the optimize flag. This is clearly a Bad Thing. Hence, even if for...else with no breaks are useless, they must be allowed.
That's not evidence of what newcomers will do. It's evidence that other languages can do things differently from Python. -- Steven D'Aprano

Steven D'Aprano wrote:
A SyntaxWarning should still be OK though - having an else clause that can only be reached in debug mode is pretty dubious in its own right. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Nick Coghlan wrote:
How about this? try: for x in xs: foo() esle: Print "foo didn't raise an exception." except: print "foo riased an exception" Using exceptions for flow control is very common in python. Or this: for x in xs: y = foo() if y is True: return else: Print "y was never True" This is perfectly acceptable in my opinion. The explicit spelling of the "else in a "for/else" is closer to. for x in xs: do something elif x == xs[-1]: do something more But that isn't reliable if x or xs is modified inside the loop. So a better way to say it is: for x in xs: do something elif for.finished: do something more But of course since a for loop isn't an object with a name, we can't look at it directly to see what it's status is. I think we just need a really nice tutorial on using for-else's. Ron

Ron Adam wrote:
The else is adding no value here. That example would be better written as: try: for x in xs: foo() print "foo didn't raise an exception." except: print "foo riased an exception"
Again, using else here is redundant and misleading. The code is clearer if it is left out entirely: for x in xs: y = foo() if y is True: return print "y was never True" The *only* time an else clause is a better alternative to just writing the code after the loop is when there is a break statement present that may skip over it. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

More completely: The else clause is useful when the for-loop is expected to _not_ exit normally, which could be by break, return or raise. So: for something in somewhere: # do something if some_condition: break elif some_other_condition: return elif some_exceptional_condition: raise SomeException else: #only execute this if the for loop falls through So the else clause will be skipped in all three early exits from the for-loop, but would run if the loop fell-through or never executed. This is useful since the alternative usually involves setting some flag before the loop and again in the body of the loop and the n testing it afterwards -- a construct I, for one, really don't like. On Sat, Oct 3, 2009 at 11:17 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- Gerald Britton

Nick Coghlan wrote:
All good points. I need another cup of coffee. ;-) There may be some obscure exception to the break-else pattern but I can't think of any at the moment. Considering the following...
Documenting for/break/else patterns seems very appropriate. +1 I suppose that it would have been clearer if it was for/then and while/then. With a break stopping the loop, and skipping over the then block. While it's much easer to explain that way, It adds a new keyword and isn't something we could or should change now I suppose. Cheers, Ron

Stephen J. Turnbull wrote:
I'm not even going to try. :-) I looked at the grammer for each of the items in question and am wondering if that could be improved in any way so that they indicate how break and continue are used in loops. Here's the current grammer for Python 3.0 loops. Break and Continue are next to each other but no where near for and while in the documentation. while_stmt ::= "while" expression ":" suite ["else" ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite] break_stmt ::= "break" continue_stmt ::= "continue" Cheers, Ron

On Fri, Oct 2, 2009 at 8:06 AM, Steven D'Aprano <steve@pearwood.info> wrote:
Concerning "if __debug__: break", I'm no expert on this subject, but I'm guessing that python does it in the following order:1. Parse 2. Compile to bytecode Also, I'm guessing optimizations occur at compilation and not in the parsing stage. So the "if __debug__: break" would parse normally and for..else won't give a syntax error. The "if __debug__" block would just be deleted at compilation time. As I said, this is just an educated guess, please correct me if I'm wrong.

I wouldn't modify the way for/else behaves btw. I would either:1. rename the "else" to something else for "for" and "while" loops 2. remove the syntax altogether. 2to3 or 3to4 can do this by changing a boolean before the "break" statement for example. expectations of those unwilling to learn the language I can tell you I love python and of course many newcomers will/do too. I'm just noting that this might be a pimple worth popping. One more thing, I have to clear django's name as it doesn't have a for/else construct, it has a for/empty construct that was inspired by a popular for/else django template recipe entitled:
"for" template tag with support for "else" if array is empty
(thanks for pointing that out Karen) On Thu, Oct 1, 2009 at 4:35 AM, alex23 <wuwei23@gmail.com> wrote:

Why single out for/while and leave out try? It supports an else statement in a similar fashion. Honestly I think the syntax is fine as it is. Once I grasped what it did and why, I exploited it to great effect. The syntax may be unfamiliar to programmers coming from other languages, but so what? The same can be said of every language on the planet. (I felt like an idiot when I started to learn Haskell). FWIW, nothing in life is intuitive. Absolutely nothing. Everything has to be learned, even the simplest things. A baby has to learn how to nurse and many struggle with that unintuitive process as well. The concept of what is "intuitive" is entirely in the eye of the beholder and is effectively a non-concept. -1. On Wed, Sep 30, 2009 at 9:58 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
-- Gerald Britton

Yuvgoog Greenle writes:
If you prefer some existing keyword, -0.75, else -1. Note: As a native speaker, since "for ... else" isn't English, I would certainly look up the semantics before using the syntax. This is very probably true for Japanese as well, who are far better at (consciously) remembering English syntax than native speakers are. I don't know about other non-natives.
2. remove the syntax altogether.
-1. It's occasionally useful, and when it is, it's nice and concise.

On Thu, Oct 1, 2009 at 1:17 AM, Stephen J. Turnbull <stephen@xemacs.org> wrote:
As another native speaker, I do find it confusing on most for loops -- so I don't use it there. It does make sense on search loops. Normal loop, where it is misleading: for item in source: process(item) else: # yikes, I would wrongly expect this to mean empty. But search loop where it makes sense: for candidate in source: if test(candidate): choice=candidate break else: choice=default (That said, even then, I tend to set the default outside the loop construct, just to avoid the else confusion.) -jJ

Yuvgoog Greenle schrieb:
I agree that the "else" clause is somewhat unintuitive. However, it has its uses and can often replace more awkward constructs. As such, I would be -1 on removing it, and -3 on reusing the else clause for some other purpose.
The block in question is called "empty" in the Django template language, not "else". If you look at the discussion that led to its introduction, you can see confusion with Python's else cited, and the tag was named "default"/"empty" because of that: http://code.djangoproject.com/ticket/6398 One template language that uses "else" for this case is Jinja (which is similar in syntax to Django templates, maybe you confused them). However, I know that Armin does know how Python's for-else works :) It is simply not useful for a (template) language that has no "break", while a "default" clause is very convenient there. Georg

I must say that calling for ... else "somewhat unintuitive" is the understatement of the year. The analogy with if ... else leads further astray than Odysseus. The feature itself is not bad. It's just that it is misnamed. I did a quick poll at the office and at IRC, five people in total, with 2-8 years of Python experience. Two had never heard of the for..else -construct; one had heard that it exists and two know about it but have never used it. Three uninitiated, in other words. All three gave similar replies: if the loop is not executed or the variable is not iterable, then the else-branch is executed. Here are their reactions, when they learned how it really works: * "It should be called for..then" (or for..finally) * "WHAT. No f** way. Completely unintuitive" * "I'd hate whoever wrote that code" These people are actual Python developers, not some newbies. And I completely agree with them. I've only once seen for...else in the wild and never used it myself. To add further insult to the naming injury, the else branch suffers from the fact that 99.9% of the time, the for-loop contains an if: for x in xs: if cond(x): break # stuff else: # more stuff My code pattern matching algorithm reads that as an indentation error. An else matches if so many times more often that decoding for..else requires unnecessary effort. I don't want the feature to be removed or even renamed (at least before Python 4). But the feature *is* badly named and unintuitive. -- [ Antti Rasinen <*> ars@iki.fi ]

Thank god for empirical evidence and thanks Antti for the measurement. This construct should have been named "finally", "didnt_break" or "not break": while self.more_points_to_check(): if self.found_it(): # Found the desired point breaknot break: # Exhausted the search space :( On Thu, Oct 1, 2009 at 2:00 PM, Antti Rasinen <ars@iki.fi> wrote:

Yuvgoog Greenle wrote:
Thank god for empirical evidence and thanks Antti for the measurement.
The plural of anecdote is not data... Although it seems the "general loop" form in Python may need to be better taught to make these semantics easier to remember :P while loop_cond: # loop body else: # else clause can be translated almost exactly as: while 1: if loop_cond: # Loop body goes here else: # Else clause goes here break The for loop form is a natural extension of that (with the implicit loop condition being "while there is stuff left in the iterable"). I can understand people not knowing what the construct means the first time they see it. But the underlying mechanics really shouldn't be all that difficult to grasp. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 8 Oct 2009 12:10:00 am Gerald Britton wrote:
Are you sure? Under what conditions would the "finally" clause be bypassed?
Are you talking about the existing try...finally clause, or the hypothetical "let's rename for...else to for...finally" clause? If the second, then it would be bypassed under exactly the same conditions as the else in for...else is bypassed. E.g.: for x in [1, 2, 3]: raise Exception else: print "This is never printed" def test(): for x in [1, 2, 3]: return x else: print "This is never printed" Renaming 'for...else' to 'for...finally' doesn't turn it into a try block. The semantics remain the same. -- Steven D'Aprano

On 2 Oct 2009, at 03:35 , Greg Ewing wrote:
Then again, a try's finally isn't *always* executed. It's *almost always* executed, but if the runtime (or just the thread the block is in) crashes, is killed with kill -9 or the machine is shut down, it won't be. Interestingly, because sys.exit throws an exception instead of killing the runtime, the finally block does run if you call sys.exit in the try block (in Java, it doesn't)

That's what I was getting at. As long as Python doesn't crash or the process is not killed by some external force (e.g. power failure), the finally clause of a try/except/finally will always be executed. On Wed, Oct 7, 2009 at 10:18 AM, Masklinn <masklinn@masklinn.net> wrote:
-- Gerald Britton

Antti Rasinen writes:
never used it. Three uninitiated, in other words.
Well, of course it's unintuitive, then. In practical programming, "unintuitive" is synonymous with "I've never used it in a real program."<wink>
Here are their reactions, when they learned how it really works:
* "It should be called for..then" (or for..finally)
I don't know about the semantics I'd guess for "then", but I think I'd consider that synonymous with "finally". IMO it's non-starter anyway because it's not already a keyword; this pattern is a little too uncommon to justify a new keyword. "finally" is no good because in try blocks it means "no matter what, do this". Having slightly different semantics in try blocks and loops would be a real loser.
I guess. However, you're a native speaker of a natural language, so I bet you can deal with idioms that are *much* less intuitive than this one, if used in context. Probably even in English (which I guess is not your native language). I find the search idiom very natural, almost intuitive (even though I've never used it myself<wink>), now that I've seen it in Nick's post. Don't you?

2009/10/1 Antti Rasinen <ars@iki.fi>:
I agree. I use it from time to time and I used to have to look up the docs every time, because I couldn't remember wheteher the 'else:' clause meant 'if did break' or 'if didn't break'. I solved this problem by stopping thinking about it as while-else or for-else, but rather as break-else. -- Arnaud

There is consistency between the use of "else" in for, while and try: The "else" suite is executed when the for/while/try statement is exhausted -- that is, is not terminated abnormally with a break, return, exception, etc. Once I got it, I GOT IT! and have found it quite handy. I don't think we should talk about changing this syntax for for/while without including the try statement. I do believe, though, that the idea is a non-starter since it would break existing code. As for the "intuitive" argument, that's a red herring. One person's "intuitive" is another's "obscure." The word is overused and undefined in any objective, measurable sense. Steve Ballmer likes it since he thinks it gives him a leg up on the competition. That should be enough for us to eschew its use. On Thu, Oct 1, 2009 at 9:54 AM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
-- Gerald Britton

On Thu, Oct 1, 2009 at 4:00 AM, Antti Rasinen <ars@iki.fi> wrote:
I must say that calling for ... else "somewhat unintuitive" is the understatement of the year.
"The nipple is the only thing that's intuitive. Everything else is learned." -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Thu, Oct 01, 2009 at 07:47:37AM -0700, Guido van Rossum wrote:
"There is no intuitive interface, not even the nipple. It's all learned." http://www.greenend.org.uk/rjk/2002/08/nipple.html Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Oleg Broytman writes:
On Thu, Oct 01, 2009 at 07:47:37AM -0700, Guido van Rossum wrote:
"The nipple is the only thing that's intuitive. Everything else is learned."
"There is no intuitive interface, not even the nipple. It's all learned."
"Although that way may not be obvious at first unless you're Dutch."

Let me rephrase - for..else is a _misleading_ construct. It suggests one thing yet does another. This response is way too long, so here's a TOC: 1. The Question Challenge - A way to examine if "for..else" is just unintuitive or misleading. 2. What can be done about for...else. 3. Lets talk about "try/else" because a few people mentioned it as though it's somehow related to the discussion. ---------------- 1. The Question Challenge - A way to examine if "for..else" is just unintuitive or misleading. Antti's experiment got me asking, you can try this as well. Ask a person who knows python the following questions: Question #1: Do you know what happens when an "else" appears after a "for" loop? if they answer yes then say nevermind. otherwise: continue to question #2. Question #2: When would the code in the "else" block execute? If you don't know, it's ok to guess. If they answer "when a break didn't occur", I'm willing to give you, the asker, up to 100 lines of patch code in whatever python project you want.. If they answer "maybe when the for loop didn't run or was an empty list" then you don't owe me anything. ------------- 2. What can be done about for...else. 1. Not allowing a for loop that has no "break" to have an "else". Just like "else" isn't allowed when there isn't an "except" in the "try". There really is no excuse, justification or sense in a "for" loop that has no "break" yet has an "else". 2. Lets not talk about removing the "else" from for/while completely since it does have its fans and cute use cases. 3. Renaming this construct for py4k wouldn't be too crazy if you use the existing reserved words "not" and "break". Look at this code and please note that it doesn't need any comments to make it readable (as opposed to Nick's example, no offence): for item in list_of_stuff: if item.is_awesome(): break not break: print("nothing is awesome :(") And I can even think of a few use cases for having just "break:". This block would execute only upon "break" occurring. That way you could have loops like this: for item in list_of_stuff: if item.is_awesome(): break break: celebrate(list_of_stuff) -------------------------- 3. Lets talk about "try/else" because a few people mentioned it as though it's somehow related to the discussion. "try/else" now _that_ is a red herring. There is no "try/else". OTOH "except/else", as I said before, is a beautiful, pythonic, useful and cool construct. This is the evidence:

On Thu, Oct 1, 2009 at 8:11 PM, Yuvgoog Greenle <ubershmekel@gmail.com>wrote:
When I see for/else I think of the second case even though I know it's not that. I think that second pattern is very common. In fact, I wrote code today that used it and I had to store the list in a variable and wrap the for in an if to test whether it was empty. Arguably, either one of these is appropriate for the word "else". I'd rather something like: for x in y: stuff else if no_break: more stuff else if no_elements: more stuff OK. This is ugly, but it's clear which of these is which use case. Surely someone can make this better in time for Python 4. --- Bruce

Yuvgoog Greenle writes:
+1. File an RFE against PyLint for sure, and against Python too. That's a *great* idea! Bikeshedding follows.
Er, no. It's more important if what people "know" is wrong than if naive guesses are wrong.
I would fire a programmer who gave an answer.<0.5 wink> He might do the same in his own code or in a review of someone else's.
Nick's example is far more readable IMO. No offense. I can tell you why, too. In his example, the "else" is immediately preceded by the "if ... break" suite. Because "break" can only happen once in a loop, I read the else as the alternative to breaking out. Sloppy, yes, but since this is the common idiom using for-else, it works for me. :-) OTOH, "break" is an imperative; "not break" looks like a prohibition to me, not the target of a branch. You could use "for: ... if not break:" but that looks ugly to me, and worse requires several tokens of lookahead to disambiguate from an ordinary if block. I'll leave it up to GvR to decide whether for-else is "less Pythonic" than try-except-else.
You'd need multiple breaks for this to make sense. Else: for item in list_of_stuff: if item.is_awesome(): celebrate(list_of_stuff) break Some people think that having multiple breaks is bad style.

2009/10/2 Stephen J. Turnbull <stephen@xemacs.org>
Nonsense - there are several other ways to break out of a loop. Raising an exception or returning for example. Michael

2009/10/2 Yuvgoog Greenle <ubershmekel@gmail.com>
The point is that the exception may be handled at an outer level - so the loop is broken out of and control flow is handed to another part of the code. Code that *always* raises an exception to break the loop is not common or interesting, but code that does so under certain circumstances is not uncommon (raising an exception is one way to break out of nested loops - the other way is an early return...)
The return may be conditional in order to explicitly break out of the loop under certain circumstances. Michael -- http://www.ironpythoninaction.com/

2009/10/2 Yuvgoog Greenle <ubershmekel@gmail.com>
Hmm... on consideration, breaking out of a loop without a break (i.e. exception or return) wouldn't enter the else clause *anyway*, so there is still no need for the else clause. My apologies, I retract. :-) Michael

I can't imagine why I'm still commenting on this thread, since there is no chance that Python will remove the "else" from for/while or put conditions on it, but here is an example of a use that has no break statement: for i, j in enumerate(something): # suite i += 1 else: i = 0 # i == number of things processed The thing here is, "i" won't be set by the "for" statement if "something" is empty. OTOH, if "something" is non-empty, i >= 1 at the end of the for-loop. Using the "else" clause in this way ensure that "i" has the number of things processed at the end of the loop. To do this without the "else" I have to: i = 0 for i, j in enumerate(something): # suite i += 1 I can't imagine why I'm still commenting on this thread, since there is no chance that Python will remove the "else" from for/while or put conditions on it, but here is an example of a use that has no break statement: for i, j in enumerate(something): # suite i += 1 else: i = 0 # i == number of things processed Does it work? Sure! But it moves the setting of "i" outside the for-construct, which I personally dislike. On Fri, Oct 2, 2009 at 8:58 AM, Michael Foord <fuzzyman@gmail.com> wrote:
-- Gerald Britton

On Fri, Oct 02, 2009 at 09:46:38AM -0400, Gerald Britton wrote:
Wrong, 'i' will always be 0 whether 'something' is empty or not. Without a 'break', 'else' is always executed. Oleg. -- Oleg Broytman http://phd.pp.ru/ phd@phd.pp.ru Programmers don't die, they just GOSUB without RETURN.

Those who believe that the for/else construct is sufficiently clear, please read this email again: Gerald Britton:
I don't mean to pick on Gerald, but he got the meaning of for/else dead wrong *in the middle of a debate about for/else*. This shows that even experienced Pythoneers who read Python-ideas can be confused about the meaning of for/else. Using it in production code means leaving a trap for the programmers who come after you and read your code to get confused and create a bug. Yes, when the others turn your working use of for/else into a bug, it's their fault for not reading the tutorial more closely so as not get confused by it, but ultimately no matter how much you blame the user, that won't stop the next guy who uses your code from misunderstanding it. The best solution to this inherent confusingness is to leave bare for/else alone for the foreseeable future, but to add a less confusing synonym for this feature. I propose "else not break:" although "elif not break:" is good too. Rewriting Gerald's example as for i, j in enumerate(something): # suite i += 1 else if not break: i = 0 # i == number of things processed makes it 100% smack you in the face obvious that "Oh yeah, this is going to set i to 0 every time, since there's no break." In an unrelated but also good idea, it would be nice to be able to do what Gerald thought he was doing: for i, j in enumerate(something): # suite i += 1 else if None: #or some other suitable phrase for "empty" i = 0 # i == number of things processed — Carl

On Sat, 3 Oct 2009 11:18:44 am Carl Johnson wrote:
Damn straight it's their fault. I hope you're not suggesting that people shouldn't use any feature that might be misunderstood by lazy, ignorant or stupid developers?
You can already do this today, with no change to the compiler, using only a slightly different syntax to that suggested: for i, j in enumerate(something): # suite i += 1 else: # if not break i = 0 Best of all, it's an extensible syntax, so there's no need for bike-shedding arguments about whether it should be spelled "not break" or "no break" or "didn't break" or "only if loop ended normally". All of these variants, and more, are accepted: for i, j in enumerate(something): # suite i += 1 else: # no break occurred and so the loop ended normally i = 0 -- Steven D'Aprano

On Fri, Oct 2, 2009 at 9:18 PM, Carl Johnson < cmjohnson.mailinglist@gmail.com> wrote:
This seems to be an argument for better documenting this behavior, rather than an argument against the behavior per se.
To me its this is even less intuitive than the bare else- first you keep that, then you commandeer "if not break" to mean "if this didn't break". There may be a better syntax out there, but no offense, I don't see this as being it.
Again, not my cup of tea. Others will doubtless disagree. Geremy Condra

Sory Carl, I did NOT get it dead wrong. The else is executed if the for loop falls through. That's the whole idea. Probably I should have set i to -1 in the else clause of the toy example though: for i, j in enumerate(something): # do something i += 1 else: i = -1 if i > 0: # we did something If you don't think the else is executed when the for-loop falls through, then you should re-read the documentation, here: http://docs.python.org/reference/compound_stmts.html#the-for-statement Where it says (just as I did, but in other words): "When the items are exhausted (which is immediately when the sequence is empty), the suite in the else clause, if present, is executed, and the loop terminates." On Fri, Oct 2, 2009 at 9:18 PM, Carl Johnson <cmjohnson.mailinglist@gmail.com> wrote:
-- Gerald Britton

Gerald Britton wrote:
The code in your example is semantically identical to the following: for i, j in enumerate(something): # do something i += 1 i = -1 if i > 0: # This block is unreachable... Without a break statement in the body of the loop the else will by executed unconditionally, hence it is exactly the same as if the code it contains was just inline after the loop body. The semantics you describe can be obtained only by initialising i before the loop: i = -1 for i, j in enumerate(something): # do something i += 1 if i >= 0: # We did something Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Yes, quite right. Another way would be: for i, j in enumerate(x): # do something i += 1 else: if "i" not in vars(): i = 0 Is it better than initializing before? Not sure. I guess it's a matter of taste. On Sat, Oct 3, 2009 at 11:22 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- Gerald Britton

Gerald Britton schrieb:
And there is STILL no need for using an else clause here. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.

On 3 Oct 2009, at 13:49 , Gerald Britton wrote:
Thus, the following `if i > 0:` clause cannot under any circumstance be executed. Your code (unless there is a break in the 'do something' part) is equivalent to: for i, j in enumerate(something): # do something i += 1 i = -1 if i > 0: # can never happen

Yuvgoog Greenle writes:
I didn't say it was nonsense and I didn't mean it was nonsense. I can see no reason at all why PyLint wouldn't warn about "breakless for-else". "raise StopIteration" and "if __debug__: break" *may* be sufficient reason Python itself shouldn't be too noisy, but for sure PyLint should warn about it.

Stephen J. Turnbull wrote:
raise StopIteration in the body of the for loop will escape, just like any other suggestion. However, Gerald's point that the else clause can also be used to give the iteration variable a "default" value (with nary a break in sight) in addition to the more traditional search loop idiom is enough to convince me that the compiler should stay out of this one. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Michael Foord writes:
Sure. Maybe I'm missing something, but consider for x in xs: function_that_may_return_or_raise(x,xs) function_that_should_not_be_executed_in_exceptional_case(xs) Now, a return or raise cannot cause f_t_s_n_b_e_i_e_c to be executed; only a break can.[1] Only a break *needs* else. If you can give a stylistic rule to distinguish when that code should be spelled instead for x in xs: function_that_may_return_or_raise(x,xs) else: function_that_should_not_be_executed_in_exceptional_case(xs) then I agree. However, if you can't, I can't either, and I can offer no reason why we shouldn't warn about breakless for-else loops since they are very often not what the user wants, and if they are desired, they can be spelled equally well without else. Footnotes: [1] StopIteration can, but I thought raising StopIteration in user code is considered quite bad form.

StopIteration once put forward on this very list as a way to stop a generator. e.g. def stop(): raise StopIteration gen = (x in something if <x meets some condition> or stop() ) Toy example: Say you want the squares of all natural numbers n such that n <= j. Here's one simple way using the stop function above: from itertools import count squares = (n**2 for n in count() if n <= j or stop() ) Without the "or stop()" the generator goes into an infinite loop when n exceeds 10. Of course you can do this toy example other ways, this is just an illustration.
-- Gerald Britton

Yuvgoog Greenle wrote:
As Stephen said, that's a very good point. Having the compiler issue a SyntaxWarning when compiling such code is perfectly possible and would make a great deal of sense (and probably prevent many cases of naive misuse).
2. Lets not talk about removing the "else" from for/while completely since it does have its fans and cute use cases.
Good :)
If you want to turn the "else" into something explicit, the phrase you're looking for would be "elif not break". I think it's better just to teach people that's what the "else" means though - no need to make them type it every time. If you want to do things in the break case then that code goes inside the body of the loop (after checking the break condition, but before the break statement itself). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, 2 Oct 2009 09:01:20 pm Nick Coghlan wrote:
I disagree that it makes sense. Why raise a SyntaxWarning for legal code? Shall we raise SyntaxWarning for the following as well? #1 pass pass #2 if False: parrot() #3 for x in []: do_something() #4 try: something() except Exception: raise etc. There are all sorts of code which is legal but does nothing. Why should the language single out one of them for a warning? If that warning is anywhere, it should be in PyLint or equivalent. It's even more problematic when you consider code where the break is inside a "if __debug__" clause. Then you've code which raises a warning when you run with the -O flag, and doesn't when you run without. -- Steven D'Aprano

Nick Coghlan wrote:
After the additional posts in the discussion, I'm back to my previous opinion - the construct should be referred to as break/else (or for/break/else and while/break/else) and we should at least investigate having the compiler itself raise at least a SyntaxWarning if it encounters a for/else or while/else construct without also encountering a break statement inside the loop. The situation is *exactly* analagous to try/except/else: if there is no except clause, then using the "else" is redundant - just put the code inside the try block (if there is also a finally clause) or ditch the try statement altogether (if there is no finally clause). The compiler enforces this by treating try/else with no except clause as a SyntaxError. For a loop with no break statements the else clause will *always* be executed, hence using the clause is completely redundant - the code it contains might as well be dedented and placed inline at the same level as the loop header. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Sat, 3 Oct 2009 03:08:49 pm Nick Coghlan wrote:
Modulo returns and exceptions.
hence using the clause is completely redundant
True. But there is an effectively infinite amount of completely redundant code possible in Python. The performance hit and maintenance burden of raising warnings for redundant code would be immense, to say nothing of the nuisance value for the developer. Such warnings don't belong in the language, they belong in PyLint or equivalent.
True, except that the else clause clearly flags it as part of the semantic unit together with the for loop. Dedenting the code flags it as separate from the for loop. Apart from free style comments, we don't have a way of flagging code blobs finer than the function -- Python doesn't work that way. For instance, we're reduced to marking logical groups of code smaller than a function with comments. # Initialise the values. x = 2 y = 3 + x z = x*y + 1 # Process the sequence. value = 0 for o in seq: value = o - value + z value = 1.0/value # Do something else with it. value = parrot(value) return cheeseshop(value) It would be interesting to hypothesise about languages that naturally grouped (e.g.) the for loop and its pre-entry and post-exit code together into one obvious code unit. Python isn't that language, but (by accident, I'm sure) the else clause comes close. -- Steven D'Aprano

Ron Adam wrote:
As I've said elsewhere in this thread, while the else clause won't be executed in those cases, neither will any code that occurs immediately after the loop statement. Accordingly, using the else clause is unnecessary and rather misleading - just writing the extra code after the loop would be much clearer. The number one thing I have learned from this thread is the fact that the else clause only makes sense when used in conjunction with a break statement and the fact that this construct isn't regularly documented and explained as for/break/else and while/break/else is the major barrier to understanding what it does. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Document it as much as you want but the "else" doesn't hint or clue as to whether it catches breaks or is skipped by them. The next problem's gonna be at midnight when you're reading code and asking yourself "hmmm, for, blah blah, else, hmm oh yeah, else-break, so this else occurs whenever there's a break." On Sat, Oct 3, 2009 at 6:27 PM, Ron Adam <rrr@ronadam.com> wrote:

Yuvgoog Greenle wrote:
True, and that is part of the other 20% I expect the documentation would't help. The only solution to that that I can think of is to change the esle's in for and while loops to for/then and while/then in Python 5.0. It might be doable, and if enough people want it, then just maybe...

On Sat, Oct 3, 2009 at 7:19 PM, Ron Adam <rrr@ronadam.com> wrote:
Documenting this syntax with the appropriate warnings and clear explanations is very important. But I don't think the amount of code mishaps on this thread are properly addressed just by better documentation. The syntax I proposed is harmless, it won't break any existing code, and it's something people in python 3 can use right now. Deprecation etc can wait for python 4. Don't tea5e me :) Of course people here would have to say if my idea sounds good or not. while still_more_items(): if found_it(): break if not break: # exhausted search space

Yuvgoog Greenle wrote:
Lol, Sorry about that. ;-), but I do think it's too late to change for/else and while/else to for/then and while/then in python 4.0 already.
I suppose most people won't like the way break is used in two entirely different ways depending on where it is. When you see a break, two things become really clear: 1: you are inside a loop 2: we are exiting a loop When you use it in the other context it makes those things a bit less obvious especially if you consider loops inside of loops. We then have to consider the closeness these too statements are to each other. if not condition: break if not break: condition we aren't exiting a loop in the second case, even though it may be inside another loop. Cheers, Ron

You do have a point and I'll meditate on it. But I do think the situation is better than you made it appear. There will usually be a linebreak. We can't help the readability of code written by people that compress code. So a more fair representation would be: if not condition: break if not break: condition (note: I'm not sure what you meant by "if not break: condition") The bad case is when you have nested loops so it would look like this... for item in list_of_items: while condition: if reason_to_stop(): break if break: # do something after the while broke if other_condition: break On Sat, Oct 3, 2009 at 7:51 PM, Ron Adam <rrr@ronadam.com> wrote:

Looking over this all again, it seems to me that the main request would be for a more explicit statement in the documentation. Something like: "When the items are exhausted (which is immediately when the sequence is empty), the suite in the else clause, if present, is executed, and the loop terminates. Note: The suite in the else clause will be executed unless the iteration is terminated with a break or return, or raises an exception that is not handled or does not return." Probably it could use some word-smithing, but is that the basic idea? One thing I DO like about the construct, though, is it makes it more apparent what code belongs together. e.g. for x in y: # suite 1 else: # suite 2 It should be obvious that suite 2 belongs with the for statement in some way. OTOH: for x in y: # suite 1 # suite 2 You can't immediately see that suite 2 is related to the for statement. You might think it is completely independent which could lead to erroneous results if you modified it without keeping the for-loop context in mind. On Sat, Oct 3, 2009 at 1:13 PM, Masklinn <masklinn@masklinn.net> wrote:
-- Gerald Britton

Masklinn wrote:
I didn't say the behavior would change. for val in vals: if cond(val): break # processing val then: #all values processed # do more stuff The break would brake out of the entire for/then block. for val in vals: if found(val): searchval = val break then: # if not found searchval = default # breaks jumps to here I think that reads very well. :-) On the other hand "else" with the same comments really isn't all that much worse once you understand how break works in for/while loops. It's just a bit more of a hurdle for people new to python to get because of it's counter intuitive behavior compared else's use in if/else blocks. In those other languages that use case blocks, break is used to escape out of the entire case block in the same way break escapes out of the entire for/else blocks in python. Cheers, Ron

On Fri, Oct 2, 2009 at 5:35 PM, Steven D'Aprano <steve@pearwood.info> wrote:
All of your examples do exactly what they appear to do. The for...else construct that has no "break" appears to do something, yet does nothing. I beg of you to try out "The Question Challenge" I posted earlier. It's a win-win situation for you. If you're still not convinced, check out this code that is legal, yet appears to do something that it doesn't: try: z = math.sqrt(x / y) except ZeroDivisionError, ValueError: print("Math error, try again") That's a real life mistake many have seen occur. Python 3 fixed this in a very elegant way. Now let's talk python 4.

On Sat, 3 Oct 2009 01:42:48 am Yuvgoog Greenle wrote:
And so does for..else with no break.
The for...else construct that has no "break" appears to do something, yet does nothing.
Nonsense.
I beg of you to try out "The Question Challenge" I posted earlier. It's a win-win situation for you.
Your second question: [quote] Question #2: When would the code in the "else" block execute? If you don't know, it's ok to guess. [...] If they answer "maybe when the for loop didn't run or was an empty list" then you don't owe me anything. [end quote] But the else clause *does* run when the loop didn't run or was an empty list. That second answer would be correct, as far as it goes. It fails to describe all the behaviour of the else clause, but it's not wrong, merely incomplete.
Irrelevant. We're not talking about the syntax of the except statement. Why would confusing syntax there convince me that a *completely different* statement was also confusing? That's like saying, "If you don't agree that chocolate tastes terrible, have a taste of this cow-vomit. Terrible, right? So now we agree, chocolate tastes terrible." -- Steven D'Aprano

*snip* *snip* On Fri, Oct 2, 2009 at 6:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
*snip* *snip* On Fri, Oct 2, 2009 at 6:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
You present 2 claims so I present 2 answers, please don't mix the two up: 1. Does "for...else" do what it appears to be doing? 2. Does python allow syntax that's likely to cause confusion or mistakes? A summary of the long answers that follow: 1. In certain cases, no it doesn't. In a few cases showcased here - comments are the only way to make the code readable. 2. Python doesn't impose silly syntax limitations, but it can and has deprecated a "legal" syntax if a more readable, not misleading, alternative can be found/created/used. ---------------- 1. Does "for...else" do what it appears to be doing? This is subjective matter so of course we can agree to disagree. Let me entertain you Steven. First of all I suggest reading through this thread and looking for code examples with for..else that were refuted, retracted, misunderstood or wrong. I can count at least 3-4 instances from here (Carl noted Gerald's but there were others as well). This isn't python-noobs either, it's python-ideas. These are good pythonistas that were mislead by the for..else syntax. Secondly, I recommend anybody interested to go ahead and try "The Question Challenge". I'll rephrase it a bit to accommodate Steven's claims. Ask a person who knows python the following questions: Question #1: Do you know what happens when an "else" appears after a "for" loop? if they answer yes then say never mind. otherwise: continue to question #2. Question #2: When does the code in the "else" block execute? Of course you don't know so it's ok to guess. If they answer "when a break didn't occur", I'm willing to give you, the asker, up to 100 lines of patch code in whatever python project you want. If they answer "only when the for loop didn't run or was an empty list" then you don't owe me anything. To remove any doubt you can ask the follow up question "So either the for loop block runs or the else block runs, but in no way both?" If you want to have some good conversation, tell them what python really does with that "else". Please don't misinterpret this Question Challenge as an attack on Python. I love Python and I have no other language. At least no other language I enjoy using :) ---------------- 2. Does python allow syntax that's likely to cause confusion or mistakes? Short answer - preferably no. It's an issue of practicality vs purity etc. Also, python tries not to have silly limitations.
It would be a silly limitation to not allow: pass pass It would be a silly limitation because there's nothing wrong with "pass-pass". Concerning our specific discussion - "pass-pass" isn't likely to cause any confusion or mistakes. So what's a "syntax that's likely to cause confusion or mistakes"? For example, the old python 2 exception instance catcher: try: # code except Exception, e: # code Sounds ok, but now check out: try: # code except ExceptionClassA, ExceptionClassB: # handle errors of both exception types That usage of the syntax is wrong because ExceptionClassB wouldn't be caught and the exception instance would be named ExceptionClassB. This appears to do one thing (catch A and catch B), yet does something completely different (catch only A as B). Python 3 FTFY with "as". So the same code in the new syntax would be: try: # code except ExceptionClassA as ExceptionClassB: # handle errors of both exception types. The fact that ExceptionClassB is an instance is much more obvious and making mistakes is harder. So yeah, python tries to avoid syntax that may cause mistakes, in other words, the python syntax strives to be as expressive as reasonably possible. Note a few things please: 1. The python 2 syntax was legal 2. For python 3 it was declared an illegal syntax. 3. It was very easy to learn the correct python 2 syntax and not make mistakes but still it was fixed for py3k. 4. Doing crazy things that made no sense became a lot harder. I know I'm happy for that. I hope it's clearer how this example is relevant to "for..else" now. The point is if the "except" syntax can change from 2to3 to make it more readable and exact, so can the for..else syntax change from 3to4. Changing for..else would be done for very similar reasons. And don't get me wrong, I like nipples, chocolate and cow vomit as much as the next guy. It's just I would really love to discuss if and/or how this problem can be resolved.

On 2 Oct 2009, at 20:43, Yuvgoog Greenle wrote:
And then ask those same people if they know what a "data descriptor" is. There's some features of a language you just have to learn. And frankly, the for/else statement is very simple. It's surprising the first time you see it, but that's because few other languages have it. But, once you learn it, it's VERY handy. On 2 Oct 2009, at 22:08, Nick Coghlan wrote:
I would disagree. Imagine, while trying to debug code, you comment out an if statement inside the for loop, and now suddenly the whole loop becomes syntactically invalid. Plus, it's not only a break that could potentially make a for/else a valid construct. Return and yield are both legitimate, and technically anything that can throw an exception is too. Trying to implement the lexer to scan for all the possible combinations does not seem to be worth the effort. Jared

On 3 Oct 2009, at 08:15 , Jared Grubb wrote:
I'm sure that's why Nick suggests a Warning, not an Error. There's no reason to make a break-less (loop) else invalid, but there are plenty of reasons to warn the programmer of such a pattern, as it's usually either pointless or erroneous.
Return and yield are both legitimate, and technically anything that can throw an exception is too.
Yes, but these are irrelevant to the for:else: or while:else: cases.

It just hit me. The for...else is so cryptic because of one big issue - the "else". Consider the following code: for obj in iterable: if found_it(obj): # Found what we were looking for! break if not break: # It wasn't there :( Similarly for while loops: while self.more_points_to_check(): if self.found_it(): # Found the desired point break if not break: # Exhausted the search space :( Notice how readable and beautiful the code has become. We have 2 implementation options: 1. an "if" that comes immediately after a for/while can have the special keywords "not" or "break". 2. the for/while syntax has an optional "if break" or "if not break". I'd like to hear if people like this idea and if so, which of the 2 options do you like better. Check it out, there's no need for a syntax error because it's so obviously wrong: for item in list_of_items: process(item) if not break: do_something() Also, now that the syntax is generic, you can add on to it whatever you like. For example: for item in list_of_items: process(item) if item.is_gold(): break if item.is_silver(): break if break and searching_for_metals: celebrate(list_of_items) --yuv

Yuvgoog Greenle wrote:
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
The compiler can't handle it - it will see the "if" as the start of a new statement. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Ok, in theory, it's possible to flag a boolean after a for/while when compiling, but I think the "special syntax" option might be simpler to implement. So let's talk grammar... The old grammar was: while_stmt ::= "while" expression ":" suite ["else" ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite] And the new one I propose looks like this: while_stmt ::= "while" expression ":" suite ["if" expression ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["if" expression ":" suite] The "if" expression would be evaluated regularly but would have a magic boolean "break" that exists only in the if statement's expression eval. Note a few things: 1. the "if" would have been evaluated either way after the loop (exceptions/returns aside). 2. the only thing that's changed is the existence of the magic boolean "break". 3. You don't have to use it as the old "for...else" but you can and it's perfectly readable. I'm no expert on the compiler, but I have a strong feeling this is doable. On Sat, Oct 3, 2009 at 6:04 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:

Yuvgoog Greenle schrieb:
Sure, almost any language change is doable if you bend over backwards far enough and break all rules of consistency. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.

Yuvgoog Greenle wrote:
It means having to several tokens ahead before being able to tell whether you're continuing the current structure or starting another. Perhaps 'elif' instead? while still_more_items(): if found_it(): break elif not break: # exhausted search space If the body of loop wasn't executed at all: while still_more_items(): if found_it(): break elif pass: # empty search space

Since we're voting, Yuvgoog Greenle writes:
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
-1 on both. In one liners (ie, comprehensions and generator expressions) I think "for ... if" is readable, but it means something else!
Also, now that the syntax is generic, you can add on to it whatever you like.
With the wind chill factor, -2. The only other syntax I've seen so far that makes any sense to me at all is for x in xs: # suite containing break then: # suite to execute after processing all xs but that would require a new keyword, so that's -1, too.

On Sat, 3 Oct 2009 11:30:55 pm Yuvgoog Greenle wrote:
No I don't. It looks like you're testing against a boolean flag called "break".
Or #3: don't change a thing.
I'd like to hear if people like this idea and if so, which of the 2 options do you like better.
No. Neither of them.
Check it out, there's no need for a syntax error
That's right.
because it's so obviously wrong:
Your reasoning is backwards. If it were obviously wrong, there *would* be need to have a syntax error:
Syntax errors are for code which can't be compiled, not for code that does something unexpected, or unintuitive, or pointless. -- Steven D'Aprano

Jared Grubb wrote:
Return and yield are both legitimate, and technically anything that can throw an exception is too.
Nope, break is unique in that it will execute the code immediately after the loop while not executing the code in the body of the else clause. "yield" and "continue" won't terminate the loop at all, while "return" and a raised exception will skip all of the code after the loop whether it is in an else clause or not. The *only* way to skip the else clause without also skipping the code immediately following the loop is to use a break statement. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Yuvgoog Greenle wrote:
There is no "try/else". OTOH "except/else", as I said before, is a beautiful, pythonic, useful and cool construct.
This is also a very good point, but perhaps not quite in the way you intended (and it relates back to your first point about the compiler not complaining about redundant else clauses on loops that contain no break statements). Just as there is no "try/else", but only "except/else", so there is no "for/else" or "while/else", but only "break/else". Issuing a SyntaxWarning might be a good way to make that clear. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, 2 Oct 2009 09:06:11 pm Nick Coghlan wrote:
Just as there is no "try/else",
Perhaps there should be. Does anyone know why there isn't? It seems an arbitrary restriction to me, because the following pieces of code are not equivalent: # not currently legal try: if cond: raise ValueError else: print "no exception was raised" finally: print "done" versus: try: if cond: raise ValueError finally: print "done" print "no exception was raised"
but only "except/else", so there is no "for/else" or "while/else", but only "break/else".
That's certainly not true.
Issuing a SyntaxWarning might be a good way to make that clear.
Such a warning would be spurious. -- Steven D'Aprano

Steven D'Aprano wrote:
Just drop the else line and you get the semantics you're after: try: if cond: raise ValueError print "no exception was raised" finally: print "done" The reason except/else is necessary is that the code in the else clause runs: 1. Outside the scope of the exception handler 2. Only if the except clause isn't taken If there is no except clause, then the code that would have been in the else clause can just be moved to the end of the try block (as in the example above). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, Oct 2, 2009 at 6:34 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Also, in English/programmer/pesudo-code/human language, the following: something: A else: B Conveys that either A occurred or B occurred. This is just something everybody is used to because everybody knows if/else. Consider the following code: except: print("A brave attempt") else: print("Yippee") It's easy to understand that either "except" occurred or "else" occurred. The only time this rule is broken in python is the for/else and while/else.

On Sat, 3 Oct 2009 01:34:34 am Nick Coghlan wrote:
It's quite surprising to me that the following two pieces of code are equivalent: try: print "Catch exceptions here" except AttributeError: # Keep the compiler happy, raise # avoid SyntaxError. else: print "Don't catch exceptions here." finally: print "Done" and: try: print "Catch exceptions here" print "Don't catch exceptions here." finally: print "Done" I've spent some time playing around with various cases, and I can't find any example where they behaviour differently, but I am still not convinced that there's not some unusual corner case where they differ. -- Steven D'Aprano

2009/10/2 Arnaud Delobelle <arnodel@googlemail.com>
But as always with Python, the code in the else clause is not protected by the except so that you do not incorrectly handle unexpected exceptions. Michael

On Fri, 2 Oct 2009 17:12:25 +0100 Michael Foord <fuzzyman@gmail.com> wrote:
Um, there's not an except clause to protect anything there. In both cases, the code flows from the try: block to the else: block (even without the else: line) and then the finally: block, with an exception in the try: or else: block skipping the rest of both. Consider the three cases: 1) no exception raised - both cases print "no exception was raised" and "done". 2) exception in original try block - both cases just print "done". 3) exception in original else - both cases print whatever prints from the else block before the exception, and then "done". So the else: might as well be a pass. <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Steven D'Aprano wrote:
According to the Language Reference, the finally clause protects all of the preceding clauses in the try statement, including the else clause. So this would be equivalent to try: if cond: raise ValueError print "no exception was raised" finally: print "done" -- Greg

On Thu, Oct 1, 2009 at 11:11 PM, Yuvgoog Greenle <ubershmekel@gmail.com>wrote:
Head on over to graphine.org- I'm getting requests for database-backed graphs and don't know enough to do it portably. I asked 4 and got 2 correct answers, but I'm happy with the promised 100 lines. If you know as little about databases as I do, take a look at the graphml code- it's out of date and probably doesn't work. Geremy Condra

On Fri, Oct 2, 2009 at 7:07 PM, geremy condra <debatem1@gmail.com> wrote:
I'm on it. I don't know much about databases, django spoiled me, but I'll try. Others don't be discouraged, go for the challenge, I'll just stack and schedule your assignments if there are any more crazy hacks that can guess this one. I'm keeping score here, and yes, I know blind faith in strangers is blind, but it's worth it if the point'll come through in the end :-) --yuv

On Thu, 1 Oct 2009 09:00:21 pm Antti Rasinen wrote:
To add further insult to the naming injury, the else branch suffers from the fact that 99.9% of the time, the for-loop contains an if:
Really? You've done a statistically significant survey of code in the wild and come to a figure accurate to one part in a thousand? Not just plucked a number straight out of thin air? In my code, the figure is more like 20-40%. Choosing one representative module at random, only one in three for-loops include an if inside the loop. And when I use for...else, it's closer to 10%.
But then there are these: for x in xs: if cond(x): process() else: process_differently() else: do_something_else() for x in xs: process() else: do_something_else() They don't look anything like an indentation error to me. -- Steven D'Aprano

Steven D'Aprano wrote:
Am I missing something? Since those examples don't have any break statements in them, why do you use an else:? -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco

On Fri, 2 Oct 2009 01:23:27 pm Robert Kern wrote:
My bad -- process and process_differently are meant to stand in for a *block*, presumably including a break, not just a function call. I was attempting to show the indent structure. I shouldn't have included the parentheses, which just muddied the water. -- Steven D'Aprano

On 2009-10-02, at 06:07, Steven D'Aprano wrote:
Oh silly me. I used some sloppy language there. I did not mean that all for-loops have ifs inside them. What does your last statistic mean? Do you have if statements in only 10% of your for..else loops or in 10% of your all for-loops (including for...else)? If you mean the first case, then please ignore the rest of this message and post an example :-) What I meant that most *for...else* structures have an if inside. The 99.9% number is, as you say, plucked from thin air -- but I think it is very close to the truth. There are simpler alternatives to for..else if the loop does not contain an if. Consider the following structure: for x in xs: # body else: # else-branch If you don't have a break in the body of the for-loop, then you don't need the else: at all. You can write the above segment as: for x in xs: # body # else-branch If, on the other hand, you do have a break in the body, then either it is conditional or it is not. If there is no break, then you are either only processing the first element in the iterable or skipping directly to the else branch. In this case it would be natural to use plain if: if xs: # body with xs[0] # else-branch Iterators complicate the matter, but even in that case then I'd rather use a peeking wrapper around xs. It seems to me that the only sensible use case for for..else is when there is an conditional break inside the loop. I'll appreciate any counter examples, of course. Nick Coghlan's had a lovely example about search loops earlier in the thread. It also highlights one of the reasons why I think the for..else construct is so rare. Consider his example: for obj in iterable: if found_it(obj): # Found what we were looking for! break else: # It wasn't there :( There are several ways of writing this without for..else. If the context for the loop is correct, you might just use return True (or obj) during the loop. No need for an else-branch there. Or you might use any: if not any(found_it(obj) for obj in iterable): # It wasn't there :( It seems to me that there often are "more intuitive" ways of writing a for..else-loop. And accordingly, the construct is rare. I'll resort to some newspeak here and define "intuitive" as either "conveys the intent of the programmer better" or as "feels like the more obvious way to do it". Pick either. --Antti -- [ ars@iki.fi <*> Antti Rasinen ] This drone-vessel speaks with the voice and authority of the Ur-Quan.

I also find for:… else: unintuitive. I know if has something to do with break, but I always forget if it means "there was no break" or "there was a break." I support the following change: for item in items: suite else: #Same as before, executes only if there was no break for item in items: suite else not break: #Executes only if there was no break. #PEP-8 should deprecate the bare else in favor of this. for item in items: suite else break: #Executes only if there was a break for item in items: suite else None: #None is a keyword now, so why not? #Executes only if there were no items or in while-loops the condition is never true I think the latter two language changes would be welcome additions to Python regardless of whether for-else stays the same in the ordinary case of not. Yes, there are ways of telling if the loop never broke or never ran the suite besides adding these grammar changes, but so what? This a fairly common pattern, and I think it would improve readability without hampering the programmer's mental model of Python any more than the existing for-else does today. If anything, this would hamper the mental model *less*. Two-cents-ly-yours, —Carl M. Johnson

Antti Rasinen wrote:
Nope, as far as I know, that's what the construct is for - search loops.
I'd agree. However, given that it is an existing construct with valid (albeit fairly uncommon) use cases, I don't see much point in messing with it. Encouraging people to refer to the idiom as "break/else" and including a SyntaxWarning for dubious usage of loop else clauses (i.e. those without an associated break statement) are probably two fairly low cost educational steps that could be taken though. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Fri, Oct 2, 2009 at 2:14 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
A SyntaxError would be more fitting for py4k but it's still not gonna make the for..else code readable. Asking people to call this construct a "break/else" is confusing because: 1. "break/else" insinuates the "else" block is for when a break statement _did_ occur. 2. the "else" is located immediately after the "for" block. Calling this anything but "for..else" is going to cause a tongue-twisting, mind boggling Stroop effect. IMHO the only way to avoid this is to rename/modify "else" to somehow convey it's relation to the break statement.

Yuvgoog Greenle wrote:
You need a much better reason than "it might confuse newbies" to justify breaking working code. In the primary intended context (search loops) the current terminology makes perfect sense: for obj in iterable: if found_it(obj): # Found what we were looking for! break else: # It wasn't there :( Similarly for while loops: while self.more_points_to_check(): if self.found_it(): # Found the desired point break else: # Exhausted the search space :( And once people learn the idiom, it is easy to remember (so long as they learn it properly - i.e. as an easy way to write a search loop with a separate handler for the "not found" case). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

On Thu, 1 Oct 2009 11:07:19 am Yuvgoog Greenle wrote:
That's a very fine distinction you are drawing, and I don't think it is useful. The else block runs when you exit the for-loop normally, by falling off the end. There are three ways to exit the for-loop without falling off the end: break, raise and return. raise and return are special: return exits the function immediately, nothing further gets run, and uncaught exceptions do similar. So the only way to exit a for-loop abnormally and still keep processing is with break. Hence you argue that the else refers to the break. But of course you can't have a break outside of a for loop, so else is equally associated with for. And in fact, it is legal to have for loops without a break but include an else. Is it useful? I don't know, but Python can't forbid them without breaking (pun not intended) code like this: for x in xs: if __debug__: break else: print "whatever" "if __debug__: suite" is special: the Python compiler optimizes the entire suite away when running with the -O flag. So if Python would treat the presence of an else as an error unless there was a break, you could have some code which was, or wasn't, legal according to the presence of the optimize flag. This is clearly a Bad Thing. Hence, even if for...else with no breaks are useless, they must be allowed.
That's not evidence of what newcomers will do. It's evidence that other languages can do things differently from Python. -- Steven D'Aprano

Steven D'Aprano wrote:
A SyntaxWarning should still be OK though - having an else clause that can only be reached in debug mode is pretty dubious in its own right. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

Nick Coghlan wrote:
How about this? try: for x in xs: foo() esle: Print "foo didn't raise an exception." except: print "foo riased an exception" Using exceptions for flow control is very common in python. Or this: for x in xs: y = foo() if y is True: return else: Print "y was never True" This is perfectly acceptable in my opinion. The explicit spelling of the "else in a "for/else" is closer to. for x in xs: do something elif x == xs[-1]: do something more But that isn't reliable if x or xs is modified inside the loop. So a better way to say it is: for x in xs: do something elif for.finished: do something more But of course since a for loop isn't an object with a name, we can't look at it directly to see what it's status is. I think we just need a really nice tutorial on using for-else's. Ron

Ron Adam wrote:
The else is adding no value here. That example would be better written as: try: for x in xs: foo() print "foo didn't raise an exception." except: print "foo riased an exception"
Again, using else here is redundant and misleading. The code is clearer if it is left out entirely: for x in xs: y = foo() if y is True: return print "y was never True" The *only* time an else clause is a better alternative to just writing the code after the loop is when there is a break statement present that may skip over it. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------

More completely: The else clause is useful when the for-loop is expected to _not_ exit normally, which could be by break, return or raise. So: for something in somewhere: # do something if some_condition: break elif some_other_condition: return elif some_exceptional_condition: raise SomeException else: #only execute this if the for loop falls through So the else clause will be skipped in all three early exits from the for-loop, but would run if the loop fell-through or never executed. This is useful since the alternative usually involves setting some flag before the loop and again in the body of the loop and the n testing it afterwards -- a construct I, for one, really don't like. On Sat, Oct 3, 2009 at 11:17 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
-- Gerald Britton

Nick Coghlan wrote:
All good points. I need another cup of coffee. ;-) There may be some obscure exception to the break-else pattern but I can't think of any at the moment. Considering the following...
Documenting for/break/else patterns seems very appropriate. +1 I suppose that it would have been clearer if it was for/then and while/then. With a break stopping the loop, and skipping over the then block. While it's much easer to explain that way, It adds a new keyword and isn't something we could or should change now I suppose. Cheers, Ron

Stephen J. Turnbull wrote:
I'm not even going to try. :-) I looked at the grammer for each of the items in question and am wondering if that could be improved in any way so that they indicate how break and continue are used in loops. Here's the current grammer for Python 3.0 loops. Break and Continue are next to each other but no where near for and while in the documentation. while_stmt ::= "while" expression ":" suite ["else" ":" suite] for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite] break_stmt ::= "break" continue_stmt ::= "continue" Cheers, Ron

On Fri, Oct 2, 2009 at 8:06 AM, Steven D'Aprano <steve@pearwood.info> wrote:
Concerning "if __debug__: break", I'm no expert on this subject, but I'm guessing that python does it in the following order:1. Parse 2. Compile to bytecode Also, I'm guessing optimizations occur at compilation and not in the parsing stage. So the "if __debug__: break" would parse normally and for..else won't give a syntax error. The "if __debug__" block would just be deleted at compilation time. As I said, this is just an educated guess, please correct me if I'm wrong.
participants (23)
-
alex23
-
Antti Rasinen
-
Arnaud Delobelle
-
Bruce Leban
-
Carl Johnson
-
Georg Brandl
-
Gerald Britton
-
geremy condra
-
Greg Ewing
-
Guido van Rossum
-
Jared Grubb
-
Jim Jewett
-
Masklinn
-
Michael Foord
-
Mike Meyer
-
MRAB
-
Nick Coghlan
-
Oleg Broytman
-
Robert Kern
-
Ron Adam
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Yuvgoog Greenle