
Switching gears a bit, here's what I want: *for_stmt* ::= "for" target_list "in" expression_list ":" suite_loop_body["except" ":" suite_if_loop_body_is_not_executed] ["else" ":" suite_if_loop_is_not_broken] The except and else appear in this order to make it clear that except takes precedence. If the loop body is not executed at all then both conditions are true but it obviously is only useful if except takes precedence. Comments? --- Bruce

On Tue, Oct 6, 2009 at 8:46 PM, Bruce Leban <bruce@leapyear.org> wrote:
I'm sure it's obvious to you what the except clause should do, but it isn't to me. :-( Assuming you're not proposing we change the meaning of else in the absence of except, and that its meaning together with except is a logical extension of this, can you show how we should translate a for-loop with an except clause into current Python? Say, what would I be writing today to get the exact effect of your proposed for i in SEQ: A except: B else: C ? -- --Guido van Rossum (home page: http://www.python.org/~guido/)

I don't like your "except" and "else" only because it's not obvious when they execute. btw your example breaks the current "for..else" search idiom. C, suite_if_loop_is_not_broken, should be labelled suite_if_loop_is_not_broken_and_not_empty in your example code. As I understand it, pythoneers need a way to know what happened with a previous loop. Did it break? Did it execute at all? The answer to both questions is either True or False and developers need these answers only after the loop finished. If python wasn't in over it's head with reserved words I would suggest adding "loop": for i in SEQ: A if not loop.broke: C # suite_if_loop_is_not_broken elif loop.empty: B # suite_if_loop_body_is_not_executed For optimization I would suggest the "loop" variable only be instantiated if it's referenced. Also, there may be better names for "loop", "broke" and "empty". Two drawbacks: 1. python's in over it's head with reserved words. 2. developers might want to use the "loop" variable a mile down from the loop which would be ugly but their fault. I'm writing a summary of the previous for/else thread and hope that by the time I finish that (a week+), someone will invent a readable, low-cost syntax (optional but awesome if it can handle all 4: break/not break/empty/not empty). On Wed, Oct 7, 2009 at 6:06 AM, Bruce Leban <bruce@leapyear.org> wrote:

2009/10/7 Yuvgoog Greenle <ubershmekel@gmail.com>:
Here's an idea with current syntax (python < 3): class Loop(object): def __init__(self, iterable): self.iterable = iterable def __iter__(self): self.broken = True self.empty = True for i in self.iterable: self.empty = False yield i self.broken = False # Example: for string in 'spam', 'bot', '': loop = Loop(string) for i in loop: if i == 'a': break print repr(string), ':' if loop.broken: print 'broken', if loop.empty: print 'empty', print # Output: 'spam' : broken 'bot' : '' : empty -- Arnaud

I'm coming to this debate rather late but ..... I did find the for ... else syntax confusing when I learned Python, and I still do a little. I would favour keeping for-loops exactly the same except allowing a more intelligible keyword instead of 'else', e.g. 'ifnobreak'. Then moving towards deprecating and ultimately forbidding the use of 'else'. Rob Cliffe ----- Original Message ----- From: "Arnaud Delobelle" <arnodel@googlemail.com> To: "Yuvgoog Greenle" <ubershmekel@gmail.com> Cc: <python-ideas@python.org> Sent: Wednesday, October 07, 2009 10:15 AM Subject: Re: [Python-ideas] for/except/else syntax 2009/10/7 Yuvgoog Greenle <ubershmekel@gmail.com>:
Here's an idea with current syntax (python < 3): class Loop(object): def __init__(self, iterable): self.iterable = iterable def __iter__(self): self.broken = True self.empty = True for i in self.iterable: self.empty = False yield i self.broken = False # Example: for string in 'spam', 'bot', '': loop = Loop(string) for i in loop: if i == 'a': break print repr(string), ':' if loop.broken: print 'broken', if loop.empty: print 'empty', print # Output: 'spam' : broken 'bot' : '' : empty -- Arnaud _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas

Yuvgoog Greenle wrote:
[snip] Perhaps: for i in SEQ: A elif not break: C # suite_if_loop_is_not_broken elif pass: B # suite_if_loop_body_is_not_executed or: for i in SEQ: A elif pass: B # suite_if_loop_body_is_not_executed else: C # suite_if_loop_is_not_broken The first possibility suggests that you could test whether there _was_ a break and well as whether there wasn't: for item in item_list: if item == desired_item: break elif break: print "Found the item" elif pass: print "No items" else: # or elif not break print "Didn't find the item" This would cause a problem in that "else" wouldn't be the default for when no elif matched, but would always mean "elif not break"! (Unless it defaulted to "elif not break" if it occurred alone.)

On Wed, Oct 7, 2009 at 10:27 AM, MRAB <python@mrabarnett.plus.com> wrote:
Some of the discussion makes it clear that it wasn't clear that my translation was for the for/except/else case and would not change the for/else case we have today. Here's a translation that covers both cases: do_except = True do_else = False for i in SEQ: do_except = False A else: do_else = True if do_except: B # suite_if_loop_body_is_not_executed elif do_else: C Regarding Guido's comment about the use of 'except' here being it makes people think of exceptions, I think it makes people think of exceptional cases too. If I could commandeer the Python time machine and rollback for/else, what I'd do is: for i in SEQ: suite except None: suite # executed if SEQ is empty except NoBreak: suite # executed if loop did not break excluding except None if present NoBreak is not a keyword; it's a special value.

On Thu, 8 Oct 2009 04:27:22 am MRAB wrote:
Here's my executive summary, for those in a hurry: -1 on any variation like "else not break" or "elif not break". +1 on aliasing "for...else" to "for...then", with identical semantics, with eventual deprecation and removal of for...else some time in the indefinite future. (Likewise for while...else.) -0 on introducing a clause that executes if the loop is never executed at all. And here are the details: Any variation like "else not break" or "elif not break" makes it look that you are testing a flag. If you think for...else is confusing now, I guarantee that this will be nothing compared to the confusion people will feel when they discover this (proposed) thing that looks like testing a flag but isn't. People will wonder where this break flag is set, and why they can't set it themselves, or even access it like any other object. (Before anyone suggests that perhaps we should introduce a global variable called "break", and allow the caller to read/write to it outside of the for loop, remember that break is a statement. It would be too abominable for words to have break a global variable and a statement at the same time.) Assuming there is consensus that for...else is confusing, my suggestion is to add an alias "then": for x in seq: ... then: suite The behaviour of "then" is identical to the current behaviour of "else", it's just another way of spelling it. Assuming consensus, eventually else would be deprecated and then removed. This has the advantage of a more natural interpretation. It seems more natural to say: run the loop, then execute suite (unless there was a break) instead of run the loop, optionally break, else execute suite. If you need to distinguish between "loop ran" and "loop didn't run at all", you don't need syntax for that, you can use the sentinel trick Ilya suggested. (You don't even need a special sentinel, just use None, provided you know None is not in the sequence you're iterating over.) But if this was so common a use-case that we needed syntax for it (and I don't believe it is), then I'd suggest: for x in seq: suite A then: suite B otherwise: suite C I'm not really enamoured of "otherwise". I'd prefer to use "else" for the case of "the loop was never entered at all", but of course that is impossible given that it currently has another meaning. -- Steven D'Aprano Operations Manager Cybersource Pty Ltd, ABN 13 053 904 082 Level 1, 130-132 Stawell St, Richmond VIC 3121 Tel: +61 3 9428 6922 Fax: +61 3 9428 6944 Web: http://www.cybersource.com.au

I was actually surprise to learn that for/else is already part of Python. I would be more happy with 'if not break', but anyway. As for `loop.empty`, this is probably what I would reserve if I was designing language from scratch, but it does seem very unpythonic to me. Note though that you can do empty = object() # sentinel ... i = empty for i in SEQ: A if i is empty: B # suite_if_loop_body_is_not_executed This requires just one more line (i=empty) per loop compared to other proposals and is completely unambiguos to both human and computer. Moreover, you can put `empty` into builtins without breaking existing programs (however, this idiom breaks in a weird case of `SEQ[-1]==empty`). On Wed, Oct 7, 2009 at 11:00 AM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:

On Tue, Oct 6, 2009 at 9:06 PM, Bruce Leban <bruce@leapyear.org> wrote:
This doesn't keep the else semantics the same; currently in a for-loop over an empty list, the else clause is still executed, but not in your case, since do_except remains true. You may have meant this intentionally but it means that adding 'except: pass' would change the semantics of a for+else loop, which I find unexpected. I now understand that you want the except clause executed when there were zero iterations (your wording "not executed" didn't mean anything to me). Naming it 'except' is a really bad idea though because it makes people thing of exception handling. I can somewhat sympathize with this desire, but I think there are already plenty of ways to do this without adding new syntax. In general the addition of new syntax ought to be a truly rare event, and with the still pending transition to Python 3.x, doubly so.
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Agree with Rob that the "else" keyword confusing in the context of a for loop. In my mind, "for each pebble in the bag, give it to Ben, or else ..." has no clear semantic meaning. What do you mean, "or else"? In my mind, better words for what "else" currently does seem to be "afterwards", "atend", "ending", "thereafter", or "subsequently". - Andrey On Wed, Oct 7, 2009 at 10:44 AM, Guido van Rossum <guido@python.org> wrote:

On 7 Oct 2009, at 11:17, Andrey Fedorov wrote:
That wouldn't have any particular meaning in Python either (in that the "else" clause would never execute). If you had an example where there *was* some use for the "else" clause, it might make more sense in an English interpretation too. Maybe something like, "for each pebble in the bag, when you get to a blue one, give it to Ben and stop, or else...". Not the best way to phrase it, but it's comprehensible.
In my mind, better words for what "else" currently does seem to be "afterwards", "atend", "ending", "thereafter", or "subsequently".
I don't think any of those really sound like what the "else" clause does... they all just sound like something to execute when the loop is done, which is what happens after the loop body anyway. Switching to any of those words would probably only make it more unintuitive. - Adam

Adam Atlas writes:
No, the else clause (as currently defined) *always* executes.
Since your intuition as expressed above is 100% wrong, I don't see how switching to any of those words could possibly hurt. :-) See Steven d'Aprano's post advocating an alternative spelling of "else" as "then" (which is a much more compact way of saying "subsequently"). Since IIRC we *still* have only one at all common use case for this facility, which looks like for thing in iterable: if thing.looks_good(): break else: thing = default_thing I'm -1 on all extensions, -1 on any multiword respelling of "else", -1 on any spelling of "else" that includes the substring "break", and -0 on renaming "else" to "then" (or something like it).

-1 on for...then Everything after the for loop is a "then": for i in SEQ: A # then # code follows The special thing about "else" is that it's skipped upon break. That's the *one and only* use case. Since the current "else" clause only tests for "if not break", I think spelling it out somehow could extremely improve "else" readability. +1 for improving the readability of "for..break..else" and not just putting the confusion under a "then" rug. --yuv

Yuvgoog Greenle:
Agreed. "Then" is not only a new keyword (=undesirable), it's not any more clear than what it replaces. It might lead to less misunderstanding of what the for-else clause does, but only because it's so opaque that those encountering it would be forced to look it up in the documentation rather than guess. But if that's the only advantage, you may as well name it "squazzlefritz" or something in Dutch. Or just do broke = False for item in items: if cond(item) broke = True break if not broke: #Pseudo else suite so that it's perfectly clear to the yahoo who comes after you what you're doing and they avoid the temptation to guess. In fact, that's what I would advise for most Python programmers to do today, unless they're completely confident that their code won't fall into the hands of yahoos at some point in the future. —Carl

On Thu, Oct 8, 2009 at 5:51 AM, Carl Johnson <cmjohnson.mailinglist@gmail.com> wrote:
Agreed. The more people disagree on how "for/else" should be spelled, the more I think there is no keyword that can encapsulate what it does unambiguously. Certainly "then" leaves me as clueless as "else" for the reasons above. I was thinking of something verbose like "elifnotbreak", but not only it is ugly, it is not 100% accurate; the correct spelling would be "elifnotbreakandnotreturnandnotexception" ;) George

On Thu, Oct 8, 2009 at 7:07 AM, George Sakkis <george.sakkis@gmail.com> wrote:
It is something that has to be learned. Now, lots of things have to be learned -- the behavior of range(1, 10) does not come naturally to many people either. But apparently for-else is used rarely enough that, given the way most people learn (by trying and by reading others' code, not by reading docs), many people don't know about it. That's a flaw, and I don't quite know what to do about it. It's about 20 years too late to remove or rename it. But we probably should not do more of these. That's a lesson. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Thu, Oct 8, 2009 at 4:07 PM, George Sakkis <george.sakkis@gmail.com> wrote:
I agree with you on "then" giving no clues but I think you're wrong about the spelling. The correct spelling would be "if not break". x = y / z if condition: print(1,2,3) The above code translated to "George Sakkis Language" should be spelled: x = y / x if condition and notreturnandnotexception: print(1,2,3) So because it's obvious that everything in python is under the condition of "notreturnandnotexception", your point is moot. The "else" in "for...break...else" is very simply a condition tested after the loop finished (exactly like any other "if" that would immediately follow the loop). The condition that's tested is simple: "if there was a break - skip this". So your spelling exaggeration doesn't worry me :). The fact that python-ideas can't agree on a better syntax for python 4/5 does. I appreciate the lesson taught, as Guido put it, but I think python can have a long term plan concerning this old, rare and misleading syntax. --yuv

The thing is, if you read the documentation, it is not misleading. It does just what it says it does. The problem Guido identified, is that too many folks don't read the documentation, but try to figure it out by reading examples. Small wonder they get confused! On Thu, Oct 8, 2009 at 8:09 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
-- Gerald Britton

On Thu, Oct 8, 2009 at 8:12 PM, Gerald Britton <gerald.britton@gmail.com>wrote:
Did you read the documentation before posting your examples? Given that you use it often enough to "fight [...] tooth and nail" over these proposals, I'm beginning to think that the construct is confusing even with the benefit of regular use. Geremy Condra

2009/10/9 Gerald Britton <gerald.britton@gmail.com>:
I read the docs as well. In fact, I used to read the docs *every time* I used the for-else construct. To me, for-else used to be confusing because although I knew very well that the else clause was about whether the loop was broken or not, I could never remember which of the two it was. It was one of these things that I couldn't learn because although I knew the dichotomy, I couldn't figure out which half of it the 'else:' referred to. It's a bit like the difference between the noun 'bow' which describes the device that throws arrows and the noun 'bow' which refers to a movement you make in the presence of royalty. I know how to pronounce them both, I just can't remember which one is which (I'm not a native english speaker)! That's why I've come to think of for-else as break-else. It makes it clear to me that the else clause is executed when the loop *didn't* break. -- Arnaud

On Sat, Oct 10, 2009 at 1:20 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: [ snip ]
something that rhymes [ snip ]
Well, we all know that poetry is a pythonic way of explaining things... After a loop, a "for" or a "while", runs the "else" along with a smile. To skip the "else" without breaking a leg, use a "break", don't boil an egg. --yuv (ps, I'd prefer the for/break/else be completely removed or renamed to something readable if-not-break or whatever. I just had a strange muse for this...)

On Fri, 9 Oct 2009 11:09:18 am Yuvgoog Greenle wrote:
That is completely incorrect. That's not what the code does. break is an unconditional jump to the end of the loop block, which includes the else suite. The following Python code: for x in seq: print "ham" if x: break else: print "spam" print "done" compiles to something like the following pseudo-code: 10: x = next item in seq 20: print "ham" 30: if x: GOTO 60 40: GOTO 10 50: print "spam" 60: print "done" The only conditional test is the test "if x". -- Steven D'Aprano

On Thu, Oct 8, 2009 at 8:09 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
Um, false analogy. The "condition" expression either doesn't raise an expression and it is evaluated in boolean context, or it does raise an exception and there is no value to evaluate. Or to put it otherwise, if "condition" evaluates to True, the hypothetical "notreturnandnotexception" is also True by definition. Regardless, even if I accepted that we don't need to emphasize the exception/return case, I'd be -1 on abusing the "break" keyword to allow "if not break". Using three keywords to express a single case is a bad design smell IMO.
So your spelling exaggeration doesn't worry me :). The fact that python-ideas can't agree on a better syntax for python 4/5 does.
The only improvement I could hope for python 4/5 was to drop this feature altogether. It's more trouble than it's worth; it saves a couple of lines at the cost of error-proneness and head scratching when reading other people's code and wondering "did he really mean this or did he misunderstand what for/else does ?". People often reject adding a do/while syntax with the argument that it can be already expressed as a loop-and-a-half, and I bet do/while is at least as common as for/else, probably more. George

On Thu, 8 Oct 2009 07:52:04 pm Yuvgoog Greenle wrote:
-1 on for...then Everything after the for loop is a "then":
What "everything after"? We're talking about a block construct. It's a self-contained syntactic unit: a for line, a code suite, an optional else line + another code suite. We're not talking about additional code (which may or may not exist) outside of the block. If I say: for x in seq: pass print "spam spam spam" print is not part of the for block. It's an independent piece of code. You can move it somewhere else: print "spam spam spam" for x in seq: pass and it's still legal. But you can't do the same with a for...else loop -- you can't move the "else" before the "for". They *have* to be executed in order: first the loop, THEN the else-suite. And break jumps to the end of the entire block: both the loop itself, and the else-suite. That's all it does.
You are incorrect. The else clause doesn't test *anything* -- it is an unconditional jump, to the end of the entire for-block. for...else is a *single* unit, as far as Python is concerned, it just happens that the else part is optional.
2 13 BREAK_LOOP 14 JUMP_ABSOLUTE 7 >> 17 POP_BLOCK 4 18 LOAD_CONST 0 ('no break') 21 PRINT_ITEM 22 PRINT_NEWLINE >> 23 LOAD_CONST 1 (None) 26 RETURN_VALUE You will notice SETUP_LOOP line. The end of the loop is the end of the else clause, not the end of the for clause.
I've gradually come to agree that "else" is an unfortunate choice of word for this keyword. It's misleading because it sounds like it executes if the loop is empty, and that's not what it does. But consider your proposal: for x in seq: ... else no break: ... It's needlessly verbose -- three words instead of one. It's easy to get confused with variants like "else break" (execute only if you *did* break), "if no break", "elif no break", "else not break", etc. If the intention is to come up with wording that people will remember, this isn't it. And lastly, it implies the existence of some magical global variable "break" which doesn't exist, and people will wonder why they can't do this: for x in seq: ... do_something() do_something_else() # now check how we exited the for loop earlier if break: print "found!" else: # or else no break: print "not found!" I guarantee that if your proposal goes ahead, folks will ask why Python doesn't expose the "break" flag outside of the for loop. The real answer is that there is no such flag, but your suggestion makes it seem like there is. -- Steven D'Aprano

On Tue, Oct 6, 2009 at 8:46 PM, Bruce Leban <bruce@leapyear.org> wrote:
I'm sure it's obvious to you what the except clause should do, but it isn't to me. :-( Assuming you're not proposing we change the meaning of else in the absence of except, and that its meaning together with except is a logical extension of this, can you show how we should translate a for-loop with an except clause into current Python? Say, what would I be writing today to get the exact effect of your proposed for i in SEQ: A except: B else: C ? -- --Guido van Rossum (home page: http://www.python.org/~guido/)

I don't like your "except" and "else" only because it's not obvious when they execute. btw your example breaks the current "for..else" search idiom. C, suite_if_loop_is_not_broken, should be labelled suite_if_loop_is_not_broken_and_not_empty in your example code. As I understand it, pythoneers need a way to know what happened with a previous loop. Did it break? Did it execute at all? The answer to both questions is either True or False and developers need these answers only after the loop finished. If python wasn't in over it's head with reserved words I would suggest adding "loop": for i in SEQ: A if not loop.broke: C # suite_if_loop_is_not_broken elif loop.empty: B # suite_if_loop_body_is_not_executed For optimization I would suggest the "loop" variable only be instantiated if it's referenced. Also, there may be better names for "loop", "broke" and "empty". Two drawbacks: 1. python's in over it's head with reserved words. 2. developers might want to use the "loop" variable a mile down from the loop which would be ugly but their fault. I'm writing a summary of the previous for/else thread and hope that by the time I finish that (a week+), someone will invent a readable, low-cost syntax (optional but awesome if it can handle all 4: break/not break/empty/not empty). On Wed, Oct 7, 2009 at 6:06 AM, Bruce Leban <bruce@leapyear.org> wrote:

2009/10/7 Yuvgoog Greenle <ubershmekel@gmail.com>:
Here's an idea with current syntax (python < 3): class Loop(object): def __init__(self, iterable): self.iterable = iterable def __iter__(self): self.broken = True self.empty = True for i in self.iterable: self.empty = False yield i self.broken = False # Example: for string in 'spam', 'bot', '': loop = Loop(string) for i in loop: if i == 'a': break print repr(string), ':' if loop.broken: print 'broken', if loop.empty: print 'empty', print # Output: 'spam' : broken 'bot' : '' : empty -- Arnaud

I'm coming to this debate rather late but ..... I did find the for ... else syntax confusing when I learned Python, and I still do a little. I would favour keeping for-loops exactly the same except allowing a more intelligible keyword instead of 'else', e.g. 'ifnobreak'. Then moving towards deprecating and ultimately forbidding the use of 'else'. Rob Cliffe ----- Original Message ----- From: "Arnaud Delobelle" <arnodel@googlemail.com> To: "Yuvgoog Greenle" <ubershmekel@gmail.com> Cc: <python-ideas@python.org> Sent: Wednesday, October 07, 2009 10:15 AM Subject: Re: [Python-ideas] for/except/else syntax 2009/10/7 Yuvgoog Greenle <ubershmekel@gmail.com>:
Here's an idea with current syntax (python < 3): class Loop(object): def __init__(self, iterable): self.iterable = iterable def __iter__(self): self.broken = True self.empty = True for i in self.iterable: self.empty = False yield i self.broken = False # Example: for string in 'spam', 'bot', '': loop = Loop(string) for i in loop: if i == 'a': break print repr(string), ':' if loop.broken: print 'broken', if loop.empty: print 'empty', print # Output: 'spam' : broken 'bot' : '' : empty -- Arnaud _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas

Yuvgoog Greenle wrote:
[snip] Perhaps: for i in SEQ: A elif not break: C # suite_if_loop_is_not_broken elif pass: B # suite_if_loop_body_is_not_executed or: for i in SEQ: A elif pass: B # suite_if_loop_body_is_not_executed else: C # suite_if_loop_is_not_broken The first possibility suggests that you could test whether there _was_ a break and well as whether there wasn't: for item in item_list: if item == desired_item: break elif break: print "Found the item" elif pass: print "No items" else: # or elif not break print "Didn't find the item" This would cause a problem in that "else" wouldn't be the default for when no elif matched, but would always mean "elif not break"! (Unless it defaulted to "elif not break" if it occurred alone.)

On Wed, Oct 7, 2009 at 10:27 AM, MRAB <python@mrabarnett.plus.com> wrote:
Some of the discussion makes it clear that it wasn't clear that my translation was for the for/except/else case and would not change the for/else case we have today. Here's a translation that covers both cases: do_except = True do_else = False for i in SEQ: do_except = False A else: do_else = True if do_except: B # suite_if_loop_body_is_not_executed elif do_else: C Regarding Guido's comment about the use of 'except' here being it makes people think of exceptions, I think it makes people think of exceptional cases too. If I could commandeer the Python time machine and rollback for/else, what I'd do is: for i in SEQ: suite except None: suite # executed if SEQ is empty except NoBreak: suite # executed if loop did not break excluding except None if present NoBreak is not a keyword; it's a special value.

On Thu, 8 Oct 2009 04:27:22 am MRAB wrote:
Here's my executive summary, for those in a hurry: -1 on any variation like "else not break" or "elif not break". +1 on aliasing "for...else" to "for...then", with identical semantics, with eventual deprecation and removal of for...else some time in the indefinite future. (Likewise for while...else.) -0 on introducing a clause that executes if the loop is never executed at all. And here are the details: Any variation like "else not break" or "elif not break" makes it look that you are testing a flag. If you think for...else is confusing now, I guarantee that this will be nothing compared to the confusion people will feel when they discover this (proposed) thing that looks like testing a flag but isn't. People will wonder where this break flag is set, and why they can't set it themselves, or even access it like any other object. (Before anyone suggests that perhaps we should introduce a global variable called "break", and allow the caller to read/write to it outside of the for loop, remember that break is a statement. It would be too abominable for words to have break a global variable and a statement at the same time.) Assuming there is consensus that for...else is confusing, my suggestion is to add an alias "then": for x in seq: ... then: suite The behaviour of "then" is identical to the current behaviour of "else", it's just another way of spelling it. Assuming consensus, eventually else would be deprecated and then removed. This has the advantage of a more natural interpretation. It seems more natural to say: run the loop, then execute suite (unless there was a break) instead of run the loop, optionally break, else execute suite. If you need to distinguish between "loop ran" and "loop didn't run at all", you don't need syntax for that, you can use the sentinel trick Ilya suggested. (You don't even need a special sentinel, just use None, provided you know None is not in the sequence you're iterating over.) But if this was so common a use-case that we needed syntax for it (and I don't believe it is), then I'd suggest: for x in seq: suite A then: suite B otherwise: suite C I'm not really enamoured of "otherwise". I'd prefer to use "else" for the case of "the loop was never entered at all", but of course that is impossible given that it currently has another meaning. -- Steven D'Aprano Operations Manager Cybersource Pty Ltd, ABN 13 053 904 082 Level 1, 130-132 Stawell St, Richmond VIC 3121 Tel: +61 3 9428 6922 Fax: +61 3 9428 6944 Web: http://www.cybersource.com.au

I was actually surprise to learn that for/else is already part of Python. I would be more happy with 'if not break', but anyway. As for `loop.empty`, this is probably what I would reserve if I was designing language from scratch, but it does seem very unpythonic to me. Note though that you can do empty = object() # sentinel ... i = empty for i in SEQ: A if i is empty: B # suite_if_loop_body_is_not_executed This requires just one more line (i=empty) per loop compared to other proposals and is completely unambiguos to both human and computer. Moreover, you can put `empty` into builtins without breaking existing programs (however, this idiom breaks in a weird case of `SEQ[-1]==empty`). On Wed, Oct 7, 2009 at 11:00 AM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:

On Tue, Oct 6, 2009 at 9:06 PM, Bruce Leban <bruce@leapyear.org> wrote:
This doesn't keep the else semantics the same; currently in a for-loop over an empty list, the else clause is still executed, but not in your case, since do_except remains true. You may have meant this intentionally but it means that adding 'except: pass' would change the semantics of a for+else loop, which I find unexpected. I now understand that you want the except clause executed when there were zero iterations (your wording "not executed" didn't mean anything to me). Naming it 'except' is a really bad idea though because it makes people thing of exception handling. I can somewhat sympathize with this desire, but I think there are already plenty of ways to do this without adding new syntax. In general the addition of new syntax ought to be a truly rare event, and with the still pending transition to Python 3.x, doubly so.
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Agree with Rob that the "else" keyword confusing in the context of a for loop. In my mind, "for each pebble in the bag, give it to Ben, or else ..." has no clear semantic meaning. What do you mean, "or else"? In my mind, better words for what "else" currently does seem to be "afterwards", "atend", "ending", "thereafter", or "subsequently". - Andrey On Wed, Oct 7, 2009 at 10:44 AM, Guido van Rossum <guido@python.org> wrote:

On 7 Oct 2009, at 11:17, Andrey Fedorov wrote:
That wouldn't have any particular meaning in Python either (in that the "else" clause would never execute). If you had an example where there *was* some use for the "else" clause, it might make more sense in an English interpretation too. Maybe something like, "for each pebble in the bag, when you get to a blue one, give it to Ben and stop, or else...". Not the best way to phrase it, but it's comprehensible.
In my mind, better words for what "else" currently does seem to be "afterwards", "atend", "ending", "thereafter", or "subsequently".
I don't think any of those really sound like what the "else" clause does... they all just sound like something to execute when the loop is done, which is what happens after the loop body anyway. Switching to any of those words would probably only make it more unintuitive. - Adam

Adam Atlas writes:
No, the else clause (as currently defined) *always* executes.
Since your intuition as expressed above is 100% wrong, I don't see how switching to any of those words could possibly hurt. :-) See Steven d'Aprano's post advocating an alternative spelling of "else" as "then" (which is a much more compact way of saying "subsequently"). Since IIRC we *still* have only one at all common use case for this facility, which looks like for thing in iterable: if thing.looks_good(): break else: thing = default_thing I'm -1 on all extensions, -1 on any multiword respelling of "else", -1 on any spelling of "else" that includes the substring "break", and -0 on renaming "else" to "then" (or something like it).

-1 on for...then Everything after the for loop is a "then": for i in SEQ: A # then # code follows The special thing about "else" is that it's skipped upon break. That's the *one and only* use case. Since the current "else" clause only tests for "if not break", I think spelling it out somehow could extremely improve "else" readability. +1 for improving the readability of "for..break..else" and not just putting the confusion under a "then" rug. --yuv

Yuvgoog Greenle:
Agreed. "Then" is not only a new keyword (=undesirable), it's not any more clear than what it replaces. It might lead to less misunderstanding of what the for-else clause does, but only because it's so opaque that those encountering it would be forced to look it up in the documentation rather than guess. But if that's the only advantage, you may as well name it "squazzlefritz" or something in Dutch. Or just do broke = False for item in items: if cond(item) broke = True break if not broke: #Pseudo else suite so that it's perfectly clear to the yahoo who comes after you what you're doing and they avoid the temptation to guess. In fact, that's what I would advise for most Python programmers to do today, unless they're completely confident that their code won't fall into the hands of yahoos at some point in the future. —Carl

On Thu, Oct 8, 2009 at 5:51 AM, Carl Johnson <cmjohnson.mailinglist@gmail.com> wrote:
Agreed. The more people disagree on how "for/else" should be spelled, the more I think there is no keyword that can encapsulate what it does unambiguously. Certainly "then" leaves me as clueless as "else" for the reasons above. I was thinking of something verbose like "elifnotbreak", but not only it is ugly, it is not 100% accurate; the correct spelling would be "elifnotbreakandnotreturnandnotexception" ;) George

On Thu, Oct 8, 2009 at 7:07 AM, George Sakkis <george.sakkis@gmail.com> wrote:
It is something that has to be learned. Now, lots of things have to be learned -- the behavior of range(1, 10) does not come naturally to many people either. But apparently for-else is used rarely enough that, given the way most people learn (by trying and by reading others' code, not by reading docs), many people don't know about it. That's a flaw, and I don't quite know what to do about it. It's about 20 years too late to remove or rename it. But we probably should not do more of these. That's a lesson. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Thu, Oct 8, 2009 at 4:07 PM, George Sakkis <george.sakkis@gmail.com> wrote:
I agree with you on "then" giving no clues but I think you're wrong about the spelling. The correct spelling would be "if not break". x = y / z if condition: print(1,2,3) The above code translated to "George Sakkis Language" should be spelled: x = y / x if condition and notreturnandnotexception: print(1,2,3) So because it's obvious that everything in python is under the condition of "notreturnandnotexception", your point is moot. The "else" in "for...break...else" is very simply a condition tested after the loop finished (exactly like any other "if" that would immediately follow the loop). The condition that's tested is simple: "if there was a break - skip this". So your spelling exaggeration doesn't worry me :). The fact that python-ideas can't agree on a better syntax for python 4/5 does. I appreciate the lesson taught, as Guido put it, but I think python can have a long term plan concerning this old, rare and misleading syntax. --yuv

The thing is, if you read the documentation, it is not misleading. It does just what it says it does. The problem Guido identified, is that too many folks don't read the documentation, but try to figure it out by reading examples. Small wonder they get confused! On Thu, Oct 8, 2009 at 8:09 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
-- Gerald Britton

On Thu, Oct 8, 2009 at 8:12 PM, Gerald Britton <gerald.britton@gmail.com>wrote:
Did you read the documentation before posting your examples? Given that you use it often enough to "fight [...] tooth and nail" over these proposals, I'm beginning to think that the construct is confusing even with the benefit of regular use. Geremy Condra

2009/10/9 Gerald Britton <gerald.britton@gmail.com>:
I read the docs as well. In fact, I used to read the docs *every time* I used the for-else construct. To me, for-else used to be confusing because although I knew very well that the else clause was about whether the loop was broken or not, I could never remember which of the two it was. It was one of these things that I couldn't learn because although I knew the dichotomy, I couldn't figure out which half of it the 'else:' referred to. It's a bit like the difference between the noun 'bow' which describes the device that throws arrows and the noun 'bow' which refers to a movement you make in the presence of royalty. I know how to pronounce them both, I just can't remember which one is which (I'm not a native english speaker)! That's why I've come to think of for-else as break-else. It makes it clear to me that the else clause is executed when the loop *didn't* break. -- Arnaud

On Sat, Oct 10, 2009 at 1:20 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: [ snip ]
something that rhymes [ snip ]
Well, we all know that poetry is a pythonic way of explaining things... After a loop, a "for" or a "while", runs the "else" along with a smile. To skip the "else" without breaking a leg, use a "break", don't boil an egg. --yuv (ps, I'd prefer the for/break/else be completely removed or renamed to something readable if-not-break or whatever. I just had a strange muse for this...)

On Fri, 9 Oct 2009 11:09:18 am Yuvgoog Greenle wrote:
That is completely incorrect. That's not what the code does. break is an unconditional jump to the end of the loop block, which includes the else suite. The following Python code: for x in seq: print "ham" if x: break else: print "spam" print "done" compiles to something like the following pseudo-code: 10: x = next item in seq 20: print "ham" 30: if x: GOTO 60 40: GOTO 10 50: print "spam" 60: print "done" The only conditional test is the test "if x". -- Steven D'Aprano

On Thu, Oct 8, 2009 at 8:09 PM, Yuvgoog Greenle <ubershmekel@gmail.com> wrote:
Um, false analogy. The "condition" expression either doesn't raise an expression and it is evaluated in boolean context, or it does raise an exception and there is no value to evaluate. Or to put it otherwise, if "condition" evaluates to True, the hypothetical "notreturnandnotexception" is also True by definition. Regardless, even if I accepted that we don't need to emphasize the exception/return case, I'd be -1 on abusing the "break" keyword to allow "if not break". Using three keywords to express a single case is a bad design smell IMO.
So your spelling exaggeration doesn't worry me :). The fact that python-ideas can't agree on a better syntax for python 4/5 does.
The only improvement I could hope for python 4/5 was to drop this feature altogether. It's more trouble than it's worth; it saves a couple of lines at the cost of error-proneness and head scratching when reading other people's code and wondering "did he really mean this or did he misunderstand what for/else does ?". People often reject adding a do/while syntax with the argument that it can be already expressed as a loop-and-a-half, and I bet do/while is at least as common as for/else, probably more. George

On Thu, 8 Oct 2009 07:52:04 pm Yuvgoog Greenle wrote:
-1 on for...then Everything after the for loop is a "then":
What "everything after"? We're talking about a block construct. It's a self-contained syntactic unit: a for line, a code suite, an optional else line + another code suite. We're not talking about additional code (which may or may not exist) outside of the block. If I say: for x in seq: pass print "spam spam spam" print is not part of the for block. It's an independent piece of code. You can move it somewhere else: print "spam spam spam" for x in seq: pass and it's still legal. But you can't do the same with a for...else loop -- you can't move the "else" before the "for". They *have* to be executed in order: first the loop, THEN the else-suite. And break jumps to the end of the entire block: both the loop itself, and the else-suite. That's all it does.
You are incorrect. The else clause doesn't test *anything* -- it is an unconditional jump, to the end of the entire for-block. for...else is a *single* unit, as far as Python is concerned, it just happens that the else part is optional.
2 13 BREAK_LOOP 14 JUMP_ABSOLUTE 7 >> 17 POP_BLOCK 4 18 LOAD_CONST 0 ('no break') 21 PRINT_ITEM 22 PRINT_NEWLINE >> 23 LOAD_CONST 1 (None) 26 RETURN_VALUE You will notice SETUP_LOOP line. The end of the loop is the end of the else clause, not the end of the for clause.
I've gradually come to agree that "else" is an unfortunate choice of word for this keyword. It's misleading because it sounds like it executes if the loop is empty, and that's not what it does. But consider your proposal: for x in seq: ... else no break: ... It's needlessly verbose -- three words instead of one. It's easy to get confused with variants like "else break" (execute only if you *did* break), "if no break", "elif no break", "else not break", etc. If the intention is to come up with wording that people will remember, this isn't it. And lastly, it implies the existence of some magical global variable "break" which doesn't exist, and people will wonder why they can't do this: for x in seq: ... do_something() do_something_else() # now check how we exited the for loop earlier if break: print "found!" else: # or else no break: print "not found!" I guarantee that if your proposal goes ahead, folks will ask why Python doesn't expose the "break" flag outside of the for loop. The real answer is that there is no such flag, but your suggestion makes it seem like there is. -- Steven D'Aprano
participants (16)
-
Adam Atlas
-
Andrey Fedorov
-
Arnaud Delobelle
-
Bruce Leban
-
Carl Johnson
-
George Sakkis
-
Gerald Britton
-
geremy condra
-
Greg Ewing
-
Guido van Rossum
-
ilya
-
MRAB
-
Rob Cliffe
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Yuvgoog Greenle