Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

for-else

7 views
Skip to first unread message

bearoph...@lycos.com

unread,
Mar 4, 2008, 8:27:56 AM3/4/08
to
So far in Python I've almost hated the 'else' of the 'for' loops:
- I have problems to remember its meaning;
- It gives me little problems when I later want to translate Python
code to other languages (and you always have to translate long-lived
code).
- I have used it only once, so far.

So so far I'd liked to see it removed from Python 3.0.

But then this article:
http://tratt.net/laurie/tech_articles/articles/the_high_risk_of_novel_language_features
has shown me that my problems with the 'else' of the 'for' mostly come
from just its bad naming. The converge language is yet another very
Python-like language, and it uses a better naming (the word
"exhausted" is long and has a complex spelling for non-English
speakers, so it's not perfect):

for ...:
...
exhausted:
...
broken:
...

The meaning is explicit. While "else" seems to mean little there.
So I may like something similar for Python 3.x (or the removal of the
"else").

Bye,
bearophile

Carl Banks

unread,
Mar 4, 2008, 10:17:39 AM3/4/08
to
On Mar 4, 8:27 am, bearophileH...@lycos.com wrote:
> So far in Python I've almost hated the 'else' of the 'for' loops:
> - I have problems to remember its meaning;
> - It gives me little problems when I later want to translate Python
> code to other languages (and you always have to translate long-lived
> code).
> - I have used it only once, so far.
>
> So so far I'd liked to see it removed from Python 3.0.
>
> But then this article:http://tratt.net/laurie/tech_articles/articles/the_high_risk_of_novel...

> has shown me that my problems with the 'else' of the 'for' mostly come
> from just its bad naming. The converge language is yet another very
> Python-like language, and it uses a better naming (the word
> "exhausted" is long and has a complex spelling for non-English
> speakers, so it's not perfect):
>
> for ...:
> ...
> exhausted:
> ...
> broken:
> ...
>
> The meaning is explicit. While "else" seems to mean little there.
> So I may like something similar for Python 3.x (or the removal of the
> "else").


I would not be opposed to this on its own merits, but there is a
rationale behind the name "else". If you consider a for loop to be a
rolled-up if...elif...else statement (situations where this is
reasonable tend to be the same ones were else would be useful), then
the "else" clause would remain unchanged on the for loop.

For instance, if you have a (trivial) if...elif...else like this:

if a == 0:
do_task_0()
elif a == 1:
do_task_1()
elif a == 2:
do_task_2()
else:
do_default_task()

You could roll it up into a for...else statement like this:

for i in range(3):
if a == i:
do_task[a]()
else:
do_default_task()

(Please never mind the trivialness of this example; I know you can
eliminate the for loop altogether; this is JUST an example.)

I keep this analogy in mind when using for...else to keep the
semantics straight.


Carl Banks

BJörn Lindqvist

unread,
Mar 4, 2008, 10:55:27 AM3/4/08
to Carl Banks, pytho...@python.org

You forgot the break statement. The else suite will always be executed
in this loop. Kind of proves bearophiles point, for-else is really
tricky.


--
mvh Björn

Tim Chase

unread,
Mar 4, 2008, 11:00:06 AM3/4/08
to Carl Banks, pytho...@python.org
> For instance, if you have a (trivial) if...elif...else like this:
>
> if a == 0:
> do_task_0()
> elif a == 1:
> do_task_1()
> elif a == 2:
> do_task_2()
> else:
> do_default_task()
>
> You could roll it up into a for...else statement like this:
>
> for i in range(3):
> if a == i:
> do_task[a]()

important "break" missing here...

> else:
> do_default_task()


or otherwise this code will do_task_i *and* do_default_task()...

-tkc


Carl Banks

unread,
Mar 4, 2008, 12:05:15 PM3/4/08
to
On Mar 4, 10:55 am, "BJörn Lindqvist" <bjou...@gmail.com> wrote:

Ah ha, but that would have been a mistake with or without the else
clause....


Carl Banks

Shane Geiger

unread,
Mar 4, 2008, 1:07:31 PM3/4/08
to pytho...@python.org

> if a == 0:
> do_task_0()
> elif a == 1:
> do_task_1()
> elif a == 2:
> do_task_2()
> else:
> do_default_task()

The if-elif-else structure that calls functions (like that above) can be
avoided with the code below:


def foo0(): print 'foo0'
def bar0(): print 'bar0'
def foo1(): print 'foo1'
def bar1(): print 'bar1'
def do_default_task(): print 'do_default_task'

do_task = { 0:foo0, 1:foo1, 2:bar0, 3:bar1, }

a = 1

# example of normal usage
if a in do_task.keys(): do_task[a]()
else: do_default_task()

# example of testing all functions in the dict as well as the default
function
for a in do_task.keys() + [8]: # 8 is a non-existent key in the do_task
dict
print "a is ",a,"and it gives this output:",
if a in do_task.keys(): do_task[a]()
else: do_default_task()

This approach works well for me:

def foo0(): print 'foo0'
def bar0(): print 'bar0'
def foo1(): print 'foo1'
def bar1(): print 'bar1'

def do_default_task(): print 'do_default_task'

do_task = { 0:foo0, 1:foo1, 2:bar0, 3:bar1, }

a = 1

# example of normal usage
if a in do_task.keys(): do_task[a]()
else: do_default_task()


# example of testing
for i in range(len(do_task.keys)):
if a in do_task.keys(): do_task[a]()
else: do_default_task()

--
Shane Geiger
IT Director
National Council on Economic Education
sge...@ncee.net | 402-438-8958 | http://www.ncee.net

Leading the Campaign for Economic and Financial Literacy

casti...@gmail.com

unread,
Mar 4, 2008, 1:40:11 PM3/4/08
to
Would you like it to be removed or its name changed?

You can do it with a special iteration:

for a in B:
if behavior
break
else:
2behavior

---->

class KeepResult:...
kr= KeepResult( B )
for a in kr:
if behavior
break
if kr.diditbreak?:
2behavior
(if not:
3behavior)

It just can't do automatic continues; you'd need a
kr.i'mcontinuingonthisone(). Would that be useful in addition?

Jeffrey Froman

unread,
Mar 4, 2008, 2:22:04 PM3/4/08
to
Carl Banks wrote:

> there is a
> rationale behind the name "else".  If you consider a for loop to be a
> rolled-up if...elif...else statement

This is an interesting angle. I've always considered "for/else" to be
unintuitive, not because of "else", but because of the coupling with "for".
Instead, I think of this as a "break/else" statement, and everything gels
for me. The same applies to my comprehension of "while/else".

I wonder how this came to be called "for/else" or "for-else". I haven't
spotted that expression in the python docs yet.

With whatever name, I find the construct quite elegant and regularly useful.


Jeffrey


Raymond Hettinger

unread,
Mar 4, 2008, 3:09:45 PM3/4/08
to
[BearOphile]

> So far in Python I've almost hated the 'else' of the 'for' loops

FWIW, I'm very happy with for-else. Most of the time, you don't need
it, but when you do, it beats the heck out of doing silly tricks with
flags.

The primary use case is searching a container:

prep_tasks()
for item in container:
if predicate(item):
found_tasks()
break
else:
not_found_tasks()
follow_up_tasks

Raymond

bearoph...@lycos.com

unread,
Mar 4, 2008, 3:27:26 PM3/4/08
to
Raymond HettInger:

> FWIW, I'm very happy with for-else. Most of the time, you don't need
> it, but when you do, it beats the heck out of doing silly tricks with
> flags.

I'd like it to be renamed to something more natural :-)

Bye,
bearophile

Terry Reedy

unread,
Mar 4, 2008, 4:40:53 PM3/4/08
to pytho...@python.org

<bearoph...@lycos.com> wrote in message
news:c4921e6c-119f-4306...@u69g2000hse.googlegroups.com...

| So far in Python I've almost hated the 'else' of the 'for' loops:
| - I have problems to remember its meaning;

Consider the following pseudoPython which you should understand:

label: loop
if cond:
do_something()
goto loop
else:
do_else()

We actually write the above as

while cond:
do_something()
else:
do_else()

Same meaning; do_else is executed when condition is false.

A for-loop is equivalent to a while loop with the condition 'iterator is
not exhausted'. So do_else when that condition is false -- the iterator is
exhausted.

Terry Jan Reedy

Ben Finney

unread,
Mar 4, 2008, 7:02:38 PM3/4/08
to
bearoph...@lycos.com writes:

> But then this article:
> http://tratt.net/laurie/tech_articles/articles/the_high_risk_of_novel_language_features
> has shown me that my problems with the 'else' of the 'for' mostly
> come from just its bad naming. The converge language is yet another
> very Python-like language, and it uses a better naming (the word
> "exhausted" is long and has a complex spelling for non-English
> speakers, so it's not perfect):
>
> for ...:
> ...
> exhausted:
> ...
> broken:
> ...

Rather than adding new keywords, I think the above would be better
spelled using the exception keywords::

for foo in bar_sequence:
# normal iteration
spam(foo)
if funky(foo):
break
except StopIteration, exc:
# the iterator stopped normally
eggs(exc)
else:
# the iterator exited abnormally, i.e. 'break'
sausage()
finally:
# always executed, even on 'break'
beans()

--
\ “[T]he question of whether machines can think [...] is about as |
`\ relevant as the question of whether submarines can swim.” |
_o__) —Edsger W. Dijkstra |
Ben Finney

casti...@gmail.com

unread,
Mar 4, 2008, 9:47:17 PM3/4/08
to
That you could do yourself, CMIIW correct me if I'm wrong.

try:
    for foo in iterex( bar_sequence ):


>         # normal iteration
>         spam(foo)
>         if funky(foo):
>             break

    except StopIterationEx, exc:


>         # the iterator stopped normally
>         eggs(exc)
>     else:
>         # the iterator exited abnormally, i.e. 'break'
>         sausage()
>     finally:
>         # always executed, even on 'break'
>         beans()

Qualm, except would be needed in every for-, and in one sense doesn't
obey the semantics of exceptions. The end of a finite list is not an
exceptional element-- it's not one. However generator semantics don't
yield finite sequences-- and finity is an exception, but for-loops
don't use infinite ones.

Makes it sound (*subj've) like I'm hacking by using for-loops..... or,
like sequencetype.__iter__ is malformed. <staggered diminished chord>

Troels Thomsen

unread,
Mar 5, 2008, 4:44:03 PM3/5/08
to

>
> The primary use case is searching a container:
>
> prep_tasks()
> for item in container:
> if predicate(item):
> found_tasks()
> break
> else:
> not_found_tasks()
> follow_up_tasks
>

I've found myself mimicing this again and again in c, and was pleased to
find it in python and use it regularely.
int i
for (i = 0 ; i < 10 ; ++i)
blah
if i == 10
not_found_tasks()

The discussion of words is silly. My surprise about "else following a for
loop.... what the heck ...." lasted excactly as long as it takes to read
this sentence.


tpt


bearoph...@lycos.com

unread,
Mar 5, 2008, 7:39:08 PM3/5/08
to

bearoph...@lycos.com

unread,
Mar 5, 2008, 7:40:56 PM3/5/08
to
Troels Thomsen:

> The discussion of words is silly. My surprise about "else following a for
> loop.... what the heck ...." lasted excactly as long as it takes to read
> this sentence.

Maybe I don't follow what you are saying, but well chosen words are a
very important part of a well designed API. If you take a look at the
Python developers mailing list you may see that people discuss days,
weeks to find the best naming for things.

Bye,
bearophile

casti...@gmail.com

unread,
Mar 5, 2008, 9:08:08 PM3/5/08
to

They should've called it "or-else". Bor hor hor. ...The keyword, I
mean.

Jeffrey Barish

unread,
Mar 6, 2008, 11:18:18 AM3/6/08
to pytho...@python.org
Terry Reedy wrote:

> A for-loop is equivalent to a while loop with the condition 'iterator is
> not exhausted'.  So do_else when that condition is false -- the iterator
> is exhausted.

I think that this is the most important statement in this thread. As others
have expressed, I too found for-else surprising when I first encountered
it. It made sense to me when I analogized for with if:

for x in range(5):
do_something()
else:
do_something_else()

means

do_something repeatedly when the condition (iterator not exhausted) is true
and do_something_else when the condition is not true, just as

if condition:
do_something()
else:
do_something_else()

means do_something once when the condition is true and do_something_else
when the condition is not true. I find it elegant that Python does not
introduce additional keywords to deal with situations that are comparable.
--
Jeffrey Barish

Sion Arrowsmith

unread,
Mar 7, 2008, 7:32:47 AM3/7/08
to
Jeffrey Barish <jeff_...@earthlink.net> wrote:
>Terry Reedy wrote:
>> A for-loop is equivalent to a while loop with the condition 'iterator is
>> not exhausted'.  So do_else when that condition is false -- the iterator
>> is exhausted.
>I think that this is the most important statement in this thread. As others
>have expressed, I too found for-else surprising when I first encountered
>it. It made sense to me when I analogized for with if: [ ... ]

And to pull those two together, I found while-else comprehensible by
analogy with if-else:

while stmt:
do_something() # stmt is True
else:
do_something_else() # stmt is False

I don't think I've ever used a for-else in the wild, but I have used
while-else. And knowing how that works, it's kind of obvious what
for-else does.

--
\S -- si...@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/
"Frankly I have no feelings towards penguins one way or the other"
-- Arthur C. Clarke
her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

egbert

unread,
Mar 8, 2008, 10:20:34 AM3/8/08
to pytho...@python.org
The idea of the if-else is:
. depending on some condition either do this or do something else,
. don't do them both.

If you approach a loop-else with this same idea, you get:
. depending on the loop conditions either do the loop,
. or do something else, but not both.

However the loop-else really works more like this:
. try to do the loop;
. if it starts but is interrupted by a break,
. then do something else as well.

So they are completely different beasts, and if you try to use
or explain the one according to the rules of the other one,
you put a serious strain on your synapses.

The explanation that the if-else and the loop-else
follow the same pattern, runs more or less like this:
. all conditions to run the loop to its completion were met,
. which means that the loop-condition is not met (any more),
. which means that we must do something else.
For me that is orwellian logic: success is failure.

The loop-else mechanism is not an easy one:
earlier in this thread Carl Banks turned it into an either/or construct
by omitting the crucial break; Jeffrey Barish initially found
the loop-else surprising; Sion Arrowsmith found it comprehensible
only after some hard thinking (as in the last paragraph).

The culprit is of course the keyword, else.
The idea of an easy follow-up after a loop is a good one.
But we need other keywords, I think at least three of them:
. skipped - the loop did not run at all
. broken - the loop was interrupted (by a break)
. exhausted - the loop ran to completion.
The last two as suggested by Laurence Tratt in his Convergence.
e
--
Egbert Bouwman - Keizersgracht 197 II - 1016 DS Amsterdam - 020 6257991
========================================================================

casti...@gmail.com

unread,
Mar 8, 2008, 3:27:14 PM3/8/08
to
> The idea of the if-else is:
> .  depending on some condition either do this or do something else,
> .  don't do them both.

yes = the loop completed.

'else' isn't rechecking a piece of the loop, it's checking the loop.
Does it test successfully--- not the loop condition, the loop? What
is 'if a loop'? Make sense, I hold it does. (Holding is good--
something I can drop and give to someone else.) If 'else' gets hit, I
didn't do the loop.

Terry Reedy

unread,
Mar 8, 2008, 4:15:31 PM3/8/08
to pytho...@python.org

"egbert" <egbert....@hccnet.nl> wrote in message
news:20080308152...@hccnet.nl...

| However the loop-else really works more like this:
| . try to do the loop;
| . if it starts but is interrupted by a break,
| . then do something else as well.

This is NOT how loop-else works for Python.
If you want to do something special on breaks,
put the break-only code before the break.

while loop_condition:
<loop statements>
if break_condition:
<break-only statements>
break
<more loop stuff>

| So they are completely different beasts, and if you try to use
| or explain the one according to the rules of the other one,
| you put a serious strain on your synapses.

I did not mean to broke your brain.

| The explanation that the if-else and the loop-else
| follow the same pattern, runs more or less like this:
| . all conditions to run the loop to its completion were met,
| . which means that the loop-condition is not met (any more),
| . which means that we must do something else.
| For me that is orwellian logic: success is failure.

I gave a clear and coherent explanation of how while derives from if,
and correspondingly, how while-else derives from if-else, to help those who
want to read and write Python code. Building on the pseudo-snippet above,
one can write

while loop_condition:
<loop statements>
if break_condition:
<break-only statements>
break
<more loop stuff>
else:
<completion-only statements>

Python allows one to have both break-only and completion-only sections
together in one compound statement and *without* having to fiddle with a
special flag variable. I am sorry if you cannot appreciate such elegance
and can only spit on it as 'orwellian'.

If the sense of else were reversed, one would have to write the clumbsier

complete = True # though false at this point
while loop_condition:
<loop statements>
if break_condition:
complete = False
break
<more loop stuff>
else:
<break-only statements>
if complete:
<completion-only statements>

Terry Jan Reedy

egbert

unread,
Mar 9, 2008, 11:38:10 AM3/9/08
to pytho...@python.org
On Sat, Mar 08, 2008 at 04:15:31PM -0500, Terry Reedy wrote:
>
> I am sorry if you cannot appreciate such elegance
> and can only spit on it as 'orwellian'.
>
I admire the elegance of your examples and your explanation.
I will keep a copy of it in my Beazley,
for I am afraid I have to read it again.
As for orwellian, I must admit
that I was quite happy when I thought of using that word,
but that it was not my luckiest thought.

But I have to persist in my malice.

In the following snippet it is not at all clear
to the naive programmer (me) that the else refers to an
iterator_is_exhausted condition,
whatever logical explanation you may offer.

. for each_item in item_list:
. do_something()
. else:
. do_else()

My temporary solution will be to accompany this else
with an appropriate comment: # exhausted

Carl Banks

unread,
Mar 10, 2008, 10:39:35 AM3/10/08
to
On Mar 8, 5:15 pm, "Terry Reedy" <tjre...@udel.edu> wrote:
> I gave a clear and coherent explanation of how while derives from if,
> and correspondingly, how while-else derives from if-else, to help those who
> want to read and write Python code. Building on the pseudo-snippet above,
> one can write
>
> while loop_condition:
> <loop statements>
> if break_condition:
> <break-only statements>
> break
> <more loop stuff>
> else:
> <completion-only statements>
>
> Python allows one to have both break-only and completion-only sections
> together in one compound statement and *without* having to fiddle with a
> special flag variable. I am sorry if you cannot appreciate such elegance
> and can only spit on it as 'orwellian'.


Just to play Devil's advocate, there is one draw drawback to "such
elegance": when there are multiple break statements. Which means
you'd have to duplicate the break-only condition, or refactor somehow
(which may or may not be suitable).

There have been a couple occasions where I felt the best solution was
to a temporary varible like so:

completed = False


while loop_condition:
<loop statements>
if break_condition:
break

<more loop stuff>
if some_other_break_condition:


break
<more loop stuff>
else:

completed = False
if not completed:
<break-only statements>

It felt icky but we're all still here so it couldn't have been that
bad.


Carl Banks

rockingred

unread,
Mar 10, 2008, 10:43:59 AM3/10/08
to
On Mar 8, 4:15 pm, "Terry Reedy" <tjre...@udel.edu> wrote:
> "egbert" <egbert.bouw...@hccnet.nl> wrote in message

Terry, instead of using "complete = True" and setting it to false on
failure, why not set "loop_completed = False" and set it to True if
the break condition is met?

Jeffrey Barish

unread,
Mar 10, 2008, 12:05:19 PM3/10/08
to pytho...@python.org
egbert wrote:

> The idea of the if-else is:
> .  depending on some condition either do this or do something else,
> .  don't do them both.

Indubitably, this statement is correct for other programming languages. I
was initially surprised by loop-else when learning Python because I
approached these constructs from the perspective of other programming
languages I knew, as you are doing. Before rejecting the Python
constructs, I asked myself whether the application of a different idea
resulted in a consistent, sensible interpretation. The key is to ask not
whether the Python constructs fit a particular idea of if-else and
loop-else, but whether a reasonable idea exists within which the Python
constructs make sense. For me and others in this thread, it does.
Different keywords would, no doubt, result in constructs that fit other
ideas better, but personally I am content with the current solution.
--
Jeffrey Barish

casti...@gmail.com

unread,
Mar 10, 2008, 12:39:59 PM3/10/08
to
> > The idea of the if-else is:
> > . depending on some condition either do this or do something else,
> > . don't do them both.
>
> constructs, I asked myself whether the application of a different idea
> resulted in a consistent, sensible interpretation.

They could just as easily have defined the else of a 'for' to mean 'if
the loop only completed not an even number of times', giving these
different outputs:

for a in [1,2,3,4,5]:
if a> 3:
break
else:
print( 'bogus' )

for b in [1,2,3,4,5]:
if b> 4:
break
else:
print( 'foo' )

Just as easily, yes. Just as well? Just as meaningfully? Just as
consistently, usefully, and sensibly?

Possibly. The meaning of 'if a loop' could be construed to mean a
parity test or a binary test (if it didn't even complete once, i.p. if
the sequence was empty). If I tell you to do a loop, and then asked
if you did it, what factors in to your answer?

The docs say, 'A break statement executed in the first suite
terminates the loop without executing the else clause's suite', for
both for- and while-.

Does for-and and while-and or for-ifso and while-ifso sound more to
your liking?

Terry Reedy

unread,
Mar 10, 2008, 11:22:37 PM3/10/08
to pytho...@python.org

"rockingred" <willst...@yahoo.ca> wrote in message
news:7a6555fa-819a-41c0...@59g2000hsb.googlegroups.com...

[OE not quoting properly]
=====================
Because completion is False when broken? Actually, I am not sure what you
mean without seeing the snippet rewritten. Certainly, one could set
'broken=False' at top (tho not true) and 'broken = True' before breaking
and test for 'not broken' at end, but that is not an improvement.

tjr

Terry Reedy

unread,
Mar 10, 2008, 11:34:56 PM3/10/08
to pytho...@python.org

"Carl Banks" <pavlove...@gmail.com> wrote in message
news:dfcf19e3-a216-461d...@n75g2000hsh.googlegroups.com...

| Just to play Devil's advocate, there is one draw drawback to "such
| elegance": when there are multiple break statements. Which means
| you'd have to duplicate the break-only condition, or refactor somehow
| (which may or may not be suitable).

Yes, I knowingly glided over the possibility of multiple break statements
with common break-only code and no completion-only code (other than
artifactual flag setting as in your code below ;-). I presume that that
triple condition is even rarer than simpler situations where one of those
conditions is false.

| There have been a couple occasions where I felt the best solution was
| to a temporary varible like so:

But I will accept your testimony that the set of such use cases is not
empty.

| completed = False
| while loop_condition:
| <loop statements>
| if break_condition:
| break
| <more loop stuff>
| if some_other_break_condition:
| break
| <more loop stuff>
| else:
| completed = False

I presume you meant True

| if not completed:
| <break-only statements>
|
| It felt icky but we're all still here so it couldn't have been that
| bad.

tjr


NickC

unread,
Mar 11, 2008, 5:43:29 AM3/11/08
to
On Mar 4, 11:27 pm, bearophileH...@lycos.com wrote:
>
> The meaning is explicit. While "else" seems to mean little there.
> So I may like something similar for Python 3.x (or the removal of the
> "else").

Consider a loop with the following form:

while 1:
if <while-cond>:
<0-to-many times code block>
else:
<0-to-1 times code block>
break

A break, return or exception in the 0-to-many times code block will
obviously skip over the 'else' part of that if statement - it will
only be executed if <while-cond> evaluates as a false value. The above
code is actually equivalent to a normal Python while-loop:

while <while-cond>:
<0-to-many times code block>
else:
<0-to-1 times code block>

For loops aren't quite so straightforward since the termination
condition is tied up with the StopIteration exception, but the clause
keeps the same name as the corresponding clause on the while loop.
Thinking of it as break-else (as someone else posted) probably isn't a
bad way to look at the situation.

Cheers,
Nick.

casti...@gmail.com

unread,
Mar 12, 2008, 3:15:09 PM3/12/08
to

Here's what try: else: says. "when control flows off the end of the
try clause." So at least their usage is consistent, even if
pessimistic. They might be using, "2. in addition to the persons or
things mentioned or implied: Who else was there?" - dictionary.com.

But conflate with 'if-else', the if and else are mutually exclusive.
Maybe the if-else should be if-orelse. One's a misnomer.

0 new messages