Mailing List Archive

1.5.2 for: else:
Hello!

The following program:

----------
for a in ['a', 12]:
print a
else:
print "Empty!"
----------

prints under 1.5.2 on Linux and Solaris:

-----
a
12
Empty!
-----

Is it a bug, or is it just me, who do not understand the feature? I
expected just "a" and "12"...

This:

----------
for a in []:
print a
else:
print "Empty!"
----------

prints:

-----
Empty!
-----

and I think it is correct.

Oleg.
----
Oleg Broytmann Netskate/Inter.Net.Ru phd@emerald.netskate.ru
Programmers don't die, they just GOSUB without RETURN.
1.5.2 for: else: [ In reply to ]
On Tue, Jul 27, 1999 at 04:15:44PM +0400, Oleg Broytmann wrote:

> The following program:

> ----------
> for a in ['a', 12]:
> print a
> else:
> print "Empty!"
> ----------

http://www.python.org/doc/current/tut/node6.html#SECTION006200000000000000000

[..]
4.4 break and continue Statements, and else Clauses on Loops

Loop statements may have an else clause; it is executed when the loop
terminates through exhaustion of the list (with for) or when the condition
becomes false (with while), but not when the loop is terminated by a break
statement.
[..]

So,

>>> def do_a(list):
... for a in list:
... if not a:
... break
... print a
... else:
... print "No FALSE items in list!"
...

>>> do_a(['a', 12])
a
12
No FALSE items in list!

>>> do_a(['a', 12, []])
a
12

>>> do_a(['a', 12, 0])
a
12

Else clauses get executed on normal loop exit, even if the loop was 'empty'.
It does not get executed when you 'break' out of a loop.

--
Thomas Wouters <thomas@xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
1.5.2 for: else: [ In reply to ]
On Tue, 27 Jul 1999, Thomas Wouters wrote:
> http://www.python.org/doc/current/tut/node6.html#SECTION006200000000000000000
>
> [..]
> 4.4 break and continue Statements, and else Clauses on Loops
>
> Loop statements may have an else clause; it is executed when the loop
> terminates through exhaustion of the list (with for) or when the condition
> becomes false (with while), but not when the loop is terminated by a break
> statement.
> [..]
[skip]
> Else clauses get executed on normal loop exit, even if the loop was 'empty'.
> It does not get executed when you 'break' out of a loop.

Aha, thanks. I expected "else" to be executed when "for" not executed on
empty list. Wrong assumption.

> --
> Thomas Wouters <thomas@xs4all.net>
>
> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!

Oleg.
----
Oleg Broytmann Netskate/Inter.Net.Ru phd@emerald.netskate.ru
Programmers don't die, they just GOSUB without RETURN.
1.5.2 for: else: [ In reply to ]
On Tue, 27 Jul 1999 14:29:43 +0200, Thomas Wouters wrote:
>On Tue, Jul 27, 1999 at 04:15:44PM +0400, Oleg Broytmann wrote:

>> The following program:
>> ----------
>> for a in ['a', 12]:
>> print a
>> else:
>> print "Empty!"
>> ----------

>http://www.python.org/doc/current/tut/node6.html#SECTION006200000000000000000

>4.4 break and continue Statements, and else Clauses on Loops

>Loop statements may have an else clause; it is executed when the loop
>terminates through exhaustion of the list (with for) or when the condition
>becomes false (with while), but not when the loop is terminated by a break
>statement.

Well, I'm suprised. I had also expected the else clause to run on empty
loop. It seems so natural, in line with the meaning of a loop (loop on
this; otherwise do that).

Fortunately I've never actually used it and thus been disenchanted.

Understanding the current semantics seems to require understanding the
nature of loop tests in Python. Since I understand them I can agree that
this makes sense, but I'm still a bit leery, because you're not 'elsing'
on the data but rather on code inside the loop.

I would _definitely_ use exceptions to handle this.

>Thomas Wouters <thomas@xs4all.net>

--
-William "Billy" Tanksley
1.5.2 for: else: [ In reply to ]
On 27 Jul 99, Oleg Broytmann wrote:

> > Loop statements may have an else clause; it is executed when the loop
> > terminates through exhaustion of the list (with for) or when the
> > condition becomes false (with while), but not when the loop is
> > terminated by a break statement. [..]
> [skip]
> > Else clauses get executed on normal loop exit, even if the loop was
> > 'empty'. It does not get executed when you 'break' out of a loop.
>
> Aha, thanks. I expected "else" to be executed when "for" not executed
> on
> empty list. Wrong assumption.

This one has bitten me too in the past. One of the few non-intuitive
parts of Python, methinks. :(

--Hans Nowak (zephyrfalcon@hvision.nl)
Homepage: http://fly.to/zephyrfalcon
Python Snippets: http://www.hvision.nl/~ivnowa/snippets/
The Purple Kookaburra Forum: http://www.delphi.com/kookaburra/
1.5.2 for: else: [ In reply to ]
William Tanksley wrote:

> Well, I'm suprised. I had also expected the else clause to run on empty
> loop. It seems so natural, in line with the meaning of a loop (loop on
> this; otherwise do that).

Hmmm, it does seem that "finally" might have been a more descriptive
choice (but historians may point out that "else" appeared before "finally"
and was thus used instead). Of course, if one breaks out of the loop, they
might reasonably expect to avoid the "finally" statement (otherwise, it
becomes redundant), and this is somewhat counter to it's "try" semantics...
Hmmm.
1.5.2 for: else: [ In reply to ]
wtanksle@dolphin.openprojects.net (William Tanksley) writes:
|On Tue, 27 Jul 1999 14:29:43 +0200, Thomas Wouters wrote:
|>On Tue, Jul 27, 1999 at 04:15:44PM +0400, Oleg Broytmann wrote:
|
|>| The following program:
|>| ----------
|>| for a in ['a', 12]:
|>| print a
|>| else:
|>| print "Empty!"
|>| ----------
|
|> http://www.python.org/doc/current/tut/node6.html#SECTION006200000000000000000
|
|> 4.4 break and continue Statements, and else Clauses on Loops
|
|> Loop statements may have an else clause; it is executed when the loop
|> terminates through exhaustion of the list (with for) or when the condition
|> becomes false (with while), but not when the loop is terminated by a break
|> statement.

| Well, I'm suprised. I had also expected the else clause to run on empty
| loop. It seems so natural, in line with the meaning of a loop (loop on
| this; otherwise do that).
|
| Fortunately I've never actually used it and thus been disenchanted.

[.(I'm confused? else clause _does_ execute after an empty loop, like
for x in ():
pass
else:
print 'for else'
)]

It seems to me to work the only useful way, so you almost can't
go wrong - at worst, if you mistake its meaning, you won't use it.
That may not be the same thing as "natural", but it's close.
It's one of the neat little things that make me pause for a moment
of appreciation when I get to use it.

| Understanding the current semantics seems to require understanding the
| nature of loop tests in Python. Since I understand them I can agree that
| this makes sense, but I'm still a bit leery, because you're not 'elsing'
| on the data but rather on code inside the loop.
|
| I would _definitely_ use exceptions to handle this.

Note that "try/except" also takes an "else", which also happens to have
the only useful sense and executes when the try block executes with no
exception. It's handy for code that should execute in the normal case
but does not itself need to be enclosed in an exception handler, so you
can focus the try block more precisely on the section that needs it.

Donn Cave, University Computing Services, University of Washington
donn@u.washington.edu
1.5.2 for: else: [ In reply to ]
William Tanksley wrote:
> On Tue, 27 Jul 1999 14:29:43 +0200, Thomas Wouters wrote:

> >4.4 break and continue Statements, and else Clauses on Loops
>
> >Loop statements may have an else clause; it is executed when the loop
> >terminates through exhaustion of the list (with for) or when the condition
> >becomes false (with while), but not when the loop is terminated by a break
> >statement.
>
> Well, I'm suprised. I had also expected the else clause to run on
> empty loop. It seems so natural, in line with the meaning of a loop
> (loop on this; otherwise do that).
>
> Fortunately I've never actually used it and thus been disenchanted.

Maybe it violated your expectations, but it's much more valuable than
what you expected. After all, testing for an empty sequence is a
no-brainer. But finding a match in a list, and testing whether you
fell off the end without finding one, is (without the else clause) a
much messier proposal.

your-disenchantment-is-my-pleasure-<wink>-ly y'rs



- Gordon
1.5.2 for: else: [ In reply to ]
On Tue, 27 Jul 1999 18:35:10 -0500, Gordon McMillan wrote:
>William Tanksley wrote:
>> On Tue, 27 Jul 1999 14:29:43 +0200, Thomas Wouters wrote:

>> >4.4 break and continue Statements, and else Clauses on Loops

>> >Loop statements may have an else clause; it is executed when the loop
>> >terminates through exhaustion of the list (with for) or when the condition
>> >becomes false (with while), but not when the loop is terminated by a break
>> >statement.

>> Well, I'm suprised. I had also expected the else clause to run on
>> empty loop. It seems so natural, in line with the meaning of a loop
>> (loop on this; otherwise do that).

>> Fortunately I've never actually used it and thus been disenchanted.

>Maybe it violated your expectations, but it's much more valuable than
>what you expected. After all, testing for an empty sequence is a
>no-brainer. But finding a match in a list, and testing whether you
>fell off the end without finding one, is (without the else clause) a
>much messier proposal.

First of all, meeting expectations is one reason why I like Python, and
therefore to me is a very valuable quality. I would go so far as to say
that it's more valuable than any amount of utility to people who have
learned and happen to remember the shibboleth.

I would also disagree with you that my interpretation would result in
disutility: you'd merely have to use exceptions instead of 'break'. This
is more in line with the way the rest of Python works, and makes the
effect of the abnormal termination of the loop perfectly clear.

The very worst part of the current else: behavior is that it changes the
meaning of else. In other constructs, else is an alternate path to take
if the data being tested fails a single expression test. In this
contruct, else is a path taken if the code block belonging to the previous
test executes a certain instruction.

Pretty odd, eh?

class neverMind(): pass

try:
for x in [1,2,3]:
print x
if x == 2: raise neverMind
except neverMind:
print "modern else clause here"

>- Gordon

--
-William "Billy" Tanksley
1.5.2 for: else: [ In reply to ]
William Tanksley <wtanksle@dolphin.openprojects.net> wrote:
> The very worst part of the current else: behavior is that it changes the
> meaning of else. In other constructs, else is an alternate path to take
> if the data being tested fails a single expression test. In this
> contruct, else is a path taken if the code block belonging to the previous
> test executes a certain instruction.

nope. you've got it all backwards. consider this:

for an "if" statement, "else" is a path taken if the
expression evaluates to false.

for a "while" statement, "else" is a path taken if the
expression evaluates to false. or in other words,
when the loop terminates by natural causes.

for a "for" statement, "else" is a path taken when
there are no more elements to loop over. or
in other words, when the loop terminates by
natural causes.

not that complicated, was it?

now, what you seem to have trouble with isn't
the "else"-clause -- it's the behaviour of "break":

"break" doesn't just break out of the inner
body (the portion between while/for and
else), it breaks out of the ENTIRE construct.
including the "else" clause. just as the docs
say.

"else" always works the same way. and so does
"break". what else did you expect from Guido?

</F>
1.5.2 for: else: [ In reply to ]
On 27 Jul 1999 23:33:58 GMT, Donn Cave wrote:
>wtanksle@dolphin.openprojects.net (William Tanksley) writes:
>|On Tue, 27 Jul 1999 14:29:43 +0200, Thomas Wouters wrote:

>|> http://www.python.org/doc/current/tut/node6.html#SECTION006200000000000000000

>|> 4.4 break and continue Statements, and else Clauses on Loops

>|> Loop statements may have an else clause; it is executed when the loop
>|> terminates through exhaustion of the list (with for) or when the condition
>|> becomes false (with while), but not when the loop is terminated by a break
>|> statement.

>| Well, I'm suprised. I had also expected the else clause to run on empty
>| loop. It seems so natural, in line with the meaning of a loop (loop on
>| this; otherwise do that).

>| Fortunately I've never actually used it and thus been disenchanted.

>[.(I'm confused? else clause _does_ execute after an empty loop, like
> for x in ():
> pass
> else:
> print 'for else'
>)]

Of course. It also executes on a full loop, or a half-full one, or for
that matter a half-empty one. The only time it doesn't execute is when
the code block _inside_ the loop happens to execute a break. Pretty odd
when you think about it.

>It seems to me to work the only useful way,

I'm sorry, I'm allergic to that phrase. I can't deny that it's useful
now, but anyone claiming that any current condition is the ONLY useful
way... Ugh. Obviously hasn't bothered even thinking about alternatives.

If there existed even a _less_ useful way you'd be wrong. And even
supposing myself to be wrong, there does exist such a way. QED.

>so you almost can't
>go wrong - at worst, if you mistake its meaning, you won't use it.

That's the problem! You _will_ use it, under the mistaken impression that
it performs some kind of useful 'else' function. Instead it performs a
hidden exception-handling. Was this leftover from some time when Python
didn't have exception handling or something?

>That may not be the same thing as "natural", but it's close.

I'm also allergic to "intuitive", and since I nearly used the word myself,
my sinuses are completely plugged. ;-)

I can't really claim natural behavior, but I do claim that both of our
problems are easily solved using other means, and my solution is
consistent with other uses of else while the current solution isn't. On
your side, of course, is the fact that the current solution IS the current
solution, no ifs ands ors or elses about it.

>It's one of the neat little things that make me pause for a moment
>of appreciation when I get to use it.

I'm pausing right now for a moment of appreciation. No, this is
incredulity. What is it about this that makes you appreciate it? I can't
see anything in it except a world-class kludge. The alternate solution,
throwing an exception, is SO much nicer that very few people even USE the
current behavior.

>| Understanding the current semantics seems to require understanding the
>| nature of loop tests in Python. Since I understand them I can agree that
>| this makes sense, but I'm still a bit leery, because you're not 'elsing'
>| on the data but rather on code inside the loop.

>| I would _definitely_ use exceptions to handle this.

>Note that "try/except" also takes an "else", which also happens to have
>the only useful sense

Hack, ack, sniffle. ;)

>and executes when the try block executes with no
>exception. It's handy for code that should execute in the normal case
>but does not itself need to be enclosed in an exception handler, so you
>can focus the try block more precisely on the section that needs it.

I agree. It's a wonderfully useful tool, and unlike either of our
solutions is pretty much irreplacable. Not as useful as 'finally', of
course.

It shares a characteristic with my solution: it executes only when the
previous control structure's block has failed to execute.

> Donn Cave, University Computing Services, University of Washington

--
-William "Billy" Tanksley
1.5.2 for: else: [ In reply to ]
William Tanksley wrote:
> On Tue, 27 Jul 1999 18:35:10 -0500, Gordon McMillan wrote:

> >Maybe it violated your expectations, but it's much more valuable than
> >what you expected. After all, testing for an empty sequence is a
> >no-brainer. But finding a match in a list, and testing whether you
> >fell off the end without finding one, is (without the else clause) a
> >much messier proposal.
[rant]
> I would also disagree with you that my interpretation would result
> in disutility: you'd merely have to use exceptions instead of
> 'break'.
[more rant]
> class neverMind(): pass
>
> try:
> for x in [1,2,3]:
> print x
> if x == 2: raise neverMind
> except neverMind:
> print "modern else clause here"

--------billy.py--------------------
class neverMind: pass

try:
for x in [1,2,3]:
print x
if x == 2: raise neverMind
except neverMind:
print "modern else clause here"

for x in [1,2,3]:
print x
if x == 2:
break
else:
print "Hi Billy!"
---------------------------------------------------

C:\TEMP>python billy.py
1
2
modern else clause here
1
2

C:\TEMP>

Notice the difference?
You need to raise the exception if you've gone through the loop and
not found 2. The best way to do that <snicker> is with an else
clause.

Or will you now claim that:

lst = [1,2,3]
for i in range(len(lst)):
if lst[i] == 2: break
if i == len(lst):
print "Tanksley else clause here"

is a better solution <wink>?

insufferably-sanctimoniously-y'rs

- Gordon
1.5.2 for: else: [ In reply to ]
On Wed, 28 Jul 1999 00:50:14 GMT, Fredrik Lundh wrote:
>William Tanksley <wtanksle@dolphin.openprojects.net> wrote:
>> The very worst part of the current else: behavior is that it changes the
>> meaning of else. In other constructs, else is an alternate path to take
>> if the data being tested fails a single expression test. In this
>> contruct, else is a path taken if the code block belonging to the previous
>> test executes a certain instruction.

>nope. you've got it all backwards. consider this:

> for an "if" statement, "else" is a path taken if the
> expression evaluates to false.

Close enough -- I would say it's the path taken if the 'if' block isn't
executed.

> for a "while" statement, "else" is a path taken if the
> expression evaluates to false. or in other words,
> when the loop terminates by natural causes.

In other words, it executes when you'd expect an 'else' to not execute --
'else' doesn't mean "natural causes".

> for a "for" statement, "else" is a path taken when
> there are no more elements to loop over. or
> in other words, when the loop terminates by
> natural causes.

In addition to the above carping, I have to add that the code following
the for (or while) loop is what I'd expect to execute after the loop
terminates.

>not that complicated, was it?

I didn't think it was either, but it seems that in spite of my initial
understanding, I still managed to reverse it accidentally.

>now, what you seem to have trouble with isn't
>the "else"-clause -- it's the behaviour of "break":

>"else" always works the same way. and so does
>"break". what else did you expect from Guido?

I expect consistency, and I expect that the major features (else with if
and else with catch) will define consistency, not minor features like else
with looping.

try:
...
except something:
...
else:
...

The else block here executes iff the except blocks don't execute.

></F>

--
-William "Billy" Tanksley
1.5.2 for: else: [ In reply to ]
On Tue, 27 Jul 1999 21:43:00 -0500, Gordon McMillan wrote:
>William Tanksley wrote:
>> On Tue, 27 Jul 1999 18:35:10 -0500, Gordon McMillan wrote:

>> >Maybe it violated your expectations, but it's much more valuable than
>> >what you expected. After all, testing for an empty sequence is a
>> >no-brainer. But finding a match in a list, and testing whether you
>> >fell off the end without finding one, is (without the else clause) a
>> >much messier proposal.
>[rant]
>> I would also disagree with you that my interpretation would result
>> in disutility: you'd merely have to use exceptions instead of
>> 'break'.
>[more rant]

>--------billy.py--------------------
>class neverMind: pass

>try:
> for x in [1,2,3]:
> print x
> if x == 2: raise neverMind
>except neverMind:
> print "modern else clause here"

>for x in [1,2,3]:
> print x
> if x == 2:
> break
>else:
> print "Hi Billy!"
>---------------------------------------------------

>C:\TEMP>python billy.py
>1
>2
>modern else clause here
>1
>2

>C:\TEMP>

>Notice the difference?
>You need to raise the exception if you've gone through the loop and
>not found 2. The best way to do that <snicker> is with an else
>clause.

Sure do! In spite of the fact that I actually did understand the modern
meaning of 'else', in practice I manage to screw it up anyhow. I can
choose to make this a commentary on my programming skill, OR on the
obtuseness of the current definition of 'else'. Hmm, which to choose,
which to choose...

:)

However, you're wrong about the best way to detect a 2 in the list using
this style. To steal the same example:

try:
for x in [1,2,3]:
print x
if x == 2: raise neverMind
print "modern else clause here"
except neverMind: print "found two"
else:
print "another place to put the modern else clause"

Wow, TMTOWTDI. Oops, did I say the wrong thing?

Of course, by demonstrating both ways to do it, I'm making the code more
complex; but you can see that this solution solves the problem quite
elegantly.

The place to use MY definition of 'else', OTOH, is when you're building a
structure during the iteration, but the result of an empty loop is
different than the initial value the variable has to have when going
through the loop.

Here you go. This example might convert a Python list into a Lisp
tree-list -- but to imitate Lisp (okay, it's a toy problem, I'm cheating)
an empty list produces NIL ~= None.

var = Node(None,None)
for x in pyList:
var.car = x
var.cdr = Node()
else:
var = None

>insufferably-sanctimoniously-y'rs

>- Gordon

unstoppably-confidantly y'rs

--
-William "Billy" Tanksley
1.5.2 for: else: [ In reply to ]
William Tanksley <wtanksle@dolphin.openprojects.net> wrote:
> > for an "if" statement, "else" is a path taken if the
> > expression evaluates to false.
>
> Close enough -- I would say it's the path taken if the 'if' block isn't
> executed.

you can say what you want, but it isn't defined
that way; the language reference says:

"If all expressions are false, the suite of
the else clause, if present, is executed."

(where "all expressions" are the expressions
for all if/elif clauses in the statement)

if you continue reading, you'll find:

"if the expression is false (which may be
the first time it is tested) the suite of the
else clause, if present, is executed"

and

"when the items are exhausted (which is
immediately when the sequence is empty),
the suite in the else clause, if present, is
executed"

for ALL these statements, the else clause is exe-
cuted if and only if ALL controlling expressions
evaluate to FALSE.

> > for a "while" statement, "else" is a path taken if the
> > expression evaluates to false. or in other words,
> > when the loop terminates by natural causes.
>
> In other words, it executes when you'd expect an 'else' to not execute --
> 'else' doesn't mean "natural causes".

huh? the "else" clause isn't involved in the loop's
termination at all; it's executed when the con-
trolling expression becomes false. if you raise
an exception, or use the break statement, or
return to the caller, you don't end up in the
"else" clause by a very simple reason: the con-
trolling expression isn't false.

> > for a "for" statement, "else" is a path taken when
> > there are no more elements to loop over. or
> > in other words, when the loop terminates by
> > natural causes.
>
> In addition to the above carping, I have to add that the code following
> the for (or while) loop is what I'd expect to execute after the loop
> terminates.

huh? the "else" clause is part of the if/while/for
statement. the code that follows the loop isn't.

I repeat:

for ALL these statements, the else clause is exe-
cuted if and only if ALL controlling expressions
evaluate to FALSE.

whether blocks are executed or not isn't part
of the definition; only the conditions are.

> I expect consistency, and I expect that the major features (else with if
> and else with catch) will define consistency, not minor features like else
> with looping.

you have consistency. for-else and while-else works
EXACTLY like if-else. for ALL these statements, the
else clause is executed if and only if ALL controlling
expressions evaluate to FALSE.

you can argue as much as you want, but that's the
way it is. you gotta live with it (unless you have your
own time machine, of course ;-)

</F>
1.5.2 for: else: [ In reply to ]
wtanksle@dolphin.openprojects.net (William Tanksley) writes:
...
| try:
| ...
| except something:
| ...
| else:
| ...
|
| The else block here executes iff the except blocks don't execute.

Beg to differ - it executes iff the try block executes to completion.
Whether an except block executes or not is immaterial.

Donn Cave, University Computing Services, University of Washington
donn@u.washington.edu
1.5.2 for: else: [ In reply to ]
Gordon McMillan wrote:
>
> But finding a match in a list, and testing whether you
> fell off the end without finding one, is (without the else clause) a
> much messier proposal.

Not if you go about it the right way. I always
put such loops in a procedure of their own,
and use return:

def find_the_holy_grail(stuff):
for x in stuff:
if is_holy_grail(x):
return x
return None

Not only does this not require a weird else
clause, it doesn't require break either. I
almost never use break - and when I do I usually
regret it later. I wouldn't mind if there weren't
any break - and without break, there would be no
need for the weird else.

Greg
1.5.2 for: else: [ In reply to ]
Fredrik Lundh wrote:
>
> what else did you expect from Guido?

I would have expected Guido to shriek in horror
and refuse to even consider such a semantically
ambiguous construct.

It seems quite out of character for both him
and Python.

Greg
1.5.2 for: else: [ In reply to ]
As I am understanding for .. else, the following

for window in self.windows:
self.ProcessWindow(window)
else:
print 'windows processed'

is the same as

for window is self.windows:
self.ProcessWindow(window)
print 'windows processed'

and the only case where the else statement has any value over simply adding
code after the for loop would be if a break statement were executed - in
which case the else would NOT be called. Personally, I would rather have
the else execute if none of the code within the for loop were executed. It
would save a variable assignment/test as in:

executed = 0
for window in self.windows:
executed = 1
self.ProcessWindow(window)
if not executed:
self.HandleProcessWindowNotCalled()

This forces the variable to be set numerous times (needless).

I'm with those that see else being an alternate execution (like the if)
rather than some sort of continuation. I'm also with those that favor "if
it isn't broke, don't fix it".

-----Original Message-----
From: Gordon McMillan [mailto:gmcm@hypernet.com]
Sent: Wednesday, July 28, 1999 4:38 PM
To: python-list@cwi.nl
Subject: Re: 1.5.2 for: else:


William Tanksley wrote:
> On Tue, 27 Jul 1999 21:43:00 -0500, Gordon McMillan wrote:

[snip Billy's silly error and his entirely insufficient embarassment
<wink>]

> However, you're wrong about the best way to detect a 2 in the list
> using this style. To steal the same example:
>
> try:
> for x in [1,2,3]:
> print x
> if x == 2: raise neverMind
> print "modern else clause here"
> except neverMind: print "found two"
> else:
> print "another place to put the modern else clause"
>
> Wow, TMTOWTDI. Oops, did I say the wrong thing?
>
> Of course, by demonstrating both ways to do it, I'm making the code
> more complex; but you can see that this solution solves the problem
> quite elegantly.

WIth an extra class, and 3 or 4 more lines of code, not to mention
treading on the toes of all who think exceptions should only be used
for exceptional conditions (or maybe it _is_ exceptional when
something you wrote works <1e3 wink>).

> The place to use MY definition of 'else', OTOH, is when you're
> building a structure during the iteration, but the result of an
> empty loop is different than the initial value the variable has to
> have when going through the loop.
>
> Here you go. This example might convert a Python list into a Lisp
> tree-list -- but to imitate Lisp (okay, it's a toy problem, I'm
> cheating) an empty list produces NIL ~= None.
>
> var = Node(None,None)
> for x in pyList:
> var.car = x
> var.cdr = Node()
> else:
> var = None

Not a Lisper, but isn't what you're doing better done thusly:

def test1(lst):
var = None
for x in lst:
var = (x, var)
return var

print `test1([1,2,3])`

print `test1([])`

Produces:
(3, (2, (1, None)))
None

> >insufferably-sanctimoniously-y'rs
>
> >- Gordon
>
> unstoppably-confidantly y'rs
>
> --
> -William "Billy" Tanksley

so-self-righteous-without-the-winks-I-might-almost-be-mistaken
-for-that-other-GM-ly y'rs

- Gordon
1.5.2 for: else: [ In reply to ]
William Tanksley wrote:
> On Tue, 27 Jul 1999 21:43:00 -0500, Gordon McMillan wrote:

[snip Billy's silly error and his entirely insufficient embarassment
<wink>]

> However, you're wrong about the best way to detect a 2 in the list
> using this style. To steal the same example:
>
> try:
> for x in [1,2,3]:
> print x
> if x == 2: raise neverMind
> print "modern else clause here"
> except neverMind: print "found two"
> else:
> print "another place to put the modern else clause"
>
> Wow, TMTOWTDI. Oops, did I say the wrong thing?
>
> Of course, by demonstrating both ways to do it, I'm making the code
> more complex; but you can see that this solution solves the problem
> quite elegantly.

WIth an extra class, and 3 or 4 more lines of code, not to mention
treading on the toes of all who think exceptions should only be used
for exceptional conditions (or maybe it _is_ exceptional when
something you wrote works <1e3 wink>).

> The place to use MY definition of 'else', OTOH, is when you're
> building a structure during the iteration, but the result of an
> empty loop is different than the initial value the variable has to
> have when going through the loop.
>
> Here you go. This example might convert a Python list into a Lisp
> tree-list -- but to imitate Lisp (okay, it's a toy problem, I'm
> cheating) an empty list produces NIL ~= None.
>
> var = Node(None,None)
> for x in pyList:
> var.car = x
> var.cdr = Node()
> else:
> var = None

Not a Lisper, but isn't what you're doing better done thusly:

def test1(lst):
var = None
for x in lst:
var = (x, var)
return var

print `test1([1,2,3])`

print `test1([])`

Produces:
(3, (2, (1, None)))
None

> >insufferably-sanctimoniously-y'rs
>
> >- Gordon
>
> unstoppably-confidantly y'rs
>
> --
> -William "Billy" Tanksley

so-self-righteous-without-the-winks-I-might-almost-be-mistaken
-for-that-other-GM-ly y'rs

- Gordon
1.5.2 for: else: [ In reply to ]
I would say that else: clause after a loop is really related to the if:
controlling the break,
rather than to the loop itself.

When I first saw Python syntax for loops I said: "A-ha! So in Python I will not
need a goto
in situations like this:
-----
for(Item* pitem=pseq->First(); pitem; pitem=pitem->Next())
if (pitem->key==42)
goto Found;

pitem = pseq->Insert(new Item());
Found:
// use item pointed to by pitem
-----
In fact, I do not see any other good use for else: clause in a loop.
Maybe the docs should just explicitly say what this feature is good for ?

Vadim

William Tanksley <wtanksle@dolphin.openprojects.net> wrote in message
news:slrn7pum9t.2ro.wtanksle@dolphin.openprojects.net...
> On Wed, 28 Jul 1999 00:50:14 GMT, Fredrik Lundh wrote:
> >William Tanksley <wtanksle@dolphin.openprojects.net> wrote:
> >> The very worst part of the current else: behavior is that it changes the
> >> meaning of else. In other constructs, else is an alternate path to take
> >> if the data being tested fails a single expression test. In this
> >> contruct, else is a path taken if the code block belonging to the previous
> >> test executes a certain instruction.
>
> >nope. you've got it all backwards. consider this:
>
> > for an "if" statement, "else" is a path taken if the
> > expression evaluates to false.
>
> Close enough -- I would say it's the path taken if the 'if' block isn't
> executed.
>
> > for a "while" statement, "else" is a path taken if the
> > expression evaluates to false. or in other words,
> > when the loop terminates by natural causes.
>
> In other words, it executes when you'd expect an 'else' to not execute --
> 'else' doesn't mean "natural causes".
>
> > for a "for" statement, "else" is a path taken when
> > there are no more elements to loop over. or
> > in other words, when the loop terminates by
> > natural causes.
>
> In addition to the above carping, I have to add that the code following
> the for (or while) loop is what I'd expect to execute after the loop
> terminates.
>
> >not that complicated, was it?
>
> I didn't think it was either, but it seems that in spite of my initial
> understanding, I still managed to reverse it accidentally.
>
> >now, what you seem to have trouble with isn't
> >the "else"-clause -- it's the behaviour of "break":
>
> >"else" always works the same way. and so does
> >"break". what else did you expect from Guido?
1.5.2 for: else: [ In reply to ]
Please show your example using the else .. I'd like to see it.

-----Original Message-----
From: Vadim Chugunov [mailto:chega_@yahoo.com]
Sent: Wednesday, July 28, 1999 4:58 PM
To: python-list@cwi.nl
Subject: Re: 1.5.2 for: else:


I would say that else: clause after a loop is really related to the if:
controlling the break,
rather than to the loop itself.

When I first saw Python syntax for loops I said: "A-ha! So in Python I will
not
need a goto
in situations like this:
-----
for(Item* pitem=pseq->First(); pitem; pitem=pitem->Next())
if (pitem->key==42)
goto Found;

pitem = pseq->Insert(new Item());
Found:
// use item pointed to by pitem
-----
In fact, I do not see any other good use for else: clause in a loop.
Maybe the docs should just explicitly say what this feature is good for ?

Vadim

William Tanksley <wtanksle@dolphin.openprojects.net> wrote in message
news:slrn7pum9t.2ro.wtanksle@dolphin.openprojects.net...
> On Wed, 28 Jul 1999 00:50:14 GMT, Fredrik Lundh wrote:
> >William Tanksley <wtanksle@dolphin.openprojects.net> wrote:
> >> The very worst part of the current else: behavior is that it changes
the
> >> meaning of else. In other constructs, else is an alternate path to
take
> >> if the data being tested fails a single expression test. In this
> >> contruct, else is a path taken if the code block belonging to the
previous
> >> test executes a certain instruction.
>
> >nope. you've got it all backwards. consider this:
>
> > for an "if" statement, "else" is a path taken if the
> > expression evaluates to false.
>
> Close enough -- I would say it's the path taken if the 'if' block isn't
> executed.
>
> > for a "while" statement, "else" is a path taken if the
> > expression evaluates to false. or in other words,
> > when the loop terminates by natural causes.
>
> In other words, it executes when you'd expect an 'else' to not execute --
> 'else' doesn't mean "natural causes".
>
> > for a "for" statement, "else" is a path taken when
> > there are no more elements to loop over. or
> > in other words, when the loop terminates by
> > natural causes.
>
> In addition to the above carping, I have to add that the code following
> the for (or while) loop is what I'd expect to execute after the loop
> terminates.
>
> >not that complicated, was it?
>
> I didn't think it was either, but it seems that in spite of my initial
> understanding, I still managed to reverse it accidentally.
>
> >now, what you seem to have trouble with isn't
> >the "else"-clause -- it's the behaviour of "break":
>
> >"else" always works the same way. and so does
> >"break". what else did you expect from Guido?
1.5.2 for: else: [ In reply to ]
How about this:

8<---------------------------------
class Item:
def __init__(self,key):
self.key = key

seq= [Item(1),Item(2),Item(3)]

for item in seq:
if item.key==42:
break
else:
item = Item(42) # oh well, append() does not return a value
seq.append(item)

print item.key
8<---------------------------------


Stidolph, David <stidolph@origin.ea.com> wrote in message
news:11A17AA2B9EAD111BCEA00A0C9B41793034AAC5B@molach.origin.ea.com...
>
> Please show your example using the else .. I'd like to see it.
>
> -----Original Message-----
> From: Vadim Chugunov [mailto:chega_@yahoo.com]
> Sent: Wednesday, July 28, 1999 4:58 PM
> To: python-list@cwi.nl
> Subject: Re: 1.5.2 for: else:
>
>
> I would say that else: clause after a loop is really related to the if:
> controlling the break,
> rather than to the loop itself.
>
> When I first saw Python syntax for loops I said: "A-ha! So in Python I will
> not
> need a goto
> in situations like this:
> -----
> for(Item* pitem=pseq->First(); pitem; pitem=pitem->Next())
> if (pitem->key==42)
> goto Found;
>
> pitem = pseq->Insert(new Item());
> Found:
> // use item pointed to by pitem
> -----
> In fact, I do not see any other good use for else: clause in a loop.
> Maybe the docs should just explicitly say what this feature is good for ?
>
> Vadim
1.5.2 for: else: [ In reply to ]
[/F, on the sparkling consistency of for/else, while/else, if/else]
> what else did you expect from Guido?

[Greg Ewing]
> I would have expected Guido to shriek in horror
> and refuse to even consider such a semantically
> ambiguous construct.
>
> It seems quite out of character for both him
> and Python.

Indeed, if for/else hadn't been in Python from the start, anyone suggesting
it would get flamed without mercy! I happen to like it, but it's Guido-like
only in its inscrutablitily at first sight <wink>. The only Pythonism less
Pythonic is that e.g.

4 < "3"

silently returns true.

although-that-would-be-even-less-pythonic-if-it-returned-false-ly y'rs -
tim
1.5.2 for: else: [ In reply to ]
William Tanksley wrote:
>
> On Tue, 27 Jul 1999 21:43:00 -0500, Gordon McMillan wrote:
> >William Tanksley wrote:
> >> On Tue, 27 Jul 1999 18:35:10 -0500, Gordon McMillan wrote:
>
> >> >Maybe it violated your expectations, but it's much more valuable than
> >> >what you expected. After all, testing for an empty sequence is a
> >> >no-brainer. But finding a match in a list, and testing whether you
> >> >fell off the end without finding one, is (without the else clause) a
> >> >much messier proposal.

If nowhere else, I would have liked something like this in Java for
testing exception-handling code. With this, I can write:

>>> try:
... print 0/0
... except ZeroDivisionError:
... print "caught exception as expected"
... else:
... print "Oops! Exception didn't happen"

whereas in Java I have to write

boolean caught = false;
try {
int a = 0 / 0;
} catch (ArithmeticException a) {
out.println("caught as expected");
caught = true;
}
if (!caught)
out.print("exception didn't happen");

I doubt if I'll often use for: else or try: else, and perhaps they could
have clearer names, but I reckon they're nice to have.

--
/\\\ Mincom | Martin Pool | martinp@mincom.com
// \\\ | Software Engineer | Phone: +61 7 3303-3333
\\ /// | Mincom Ltd. |
\/// | Teneriffe, Brisbane | Speaking for myself only

1 2  View All