By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,117 Members | 2,142 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,117 IT Pros & Developers. It's quick & easy.

"for" with "else"?

P: n/a
While trying to print a none empty list, I accidentaly put an "else"
statement with a "for" instead of "if". Here is what I had:

if ( len(mylist)> 0) :
for x,y in mylist:
print x,y
else:
print "Empty list"

which was supposed to be:

if ( len(mylist)> 0) :
for x,y in mylist:
print x,y
else:
print "Empty list"
Is this to be expected?
(python 2.2.2)

++++++++++++++++++++++++++++++=
for x in range(5):

.... print x*x
.... else:
.... print "done"
....
0
1
4
9
16
done
++++++++++++++++++++++++++++++=

Jul 18 '05 #1
Share this Question
Share on Google+
23 Replies


P: n/a
[Invalid User wrote]
While trying to print a none empty list, I accidentaly put an "else"
statement with a "for" instead of "if". Here is what I had:


From the Python Language Reference

"""
The for statement

for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]

The expression list is evaluated once; it should yield a sequence. The
suite is then executed once for each item in the sequence, in the
order of ascending indices. Each item in turn is assigned to the
target list using the standard rules for assignments, and then the
suite is executed. When the items are exhausted (which is immediately
when the sequence is empty), the suite in the else clause, if present,
is executed, and the loop terminates.
"""

http://www.python.org/doc/current/ref/for.html

A quick glance through the archives confirms that this has been the
case since at least python 1.4:-

http://www.python.org/doc/1.4/ref/ref7.html#HDR2

regards,

--
alan kennedy
-----------------------------------------------------
check http headers here: http://xhaus.com/headers
email alan: http://xhaus.com/mailto/alan
Jul 18 '05 #2

P: n/a
Invalid User <us**@invalid.domain> writes:
Is this to be expected?
(python 2.2.2)

++++++++++++++++++++++++++++++=
>>> for x in range(5): .... print x*x
.... else:
.... print "done"
....
0
1
4
9
16
done
++++++++++++++++++++++++++++++=


Yes. The else clause is invoked iff the for loop terminates normally.
Contrast with:

++++++++++++++++++++++++++++++
for x in range(5): .... print x*x
.... if x==4:
.... break
.... else:
.... print "did all"
....
0
1
4
9
16

++++++++++++++++++++++++++++++

(This happens to be the *reverse* of what my intuition expects - it
would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and
one must simply remember it.)

--
Mark Jackson - http://www.alumni.caltech.edu/~mjackson
There are no foolish questions and no man becomes a fool
until he has stopped asking questions.
- Charles P. Steinmetz
Jul 18 '05 #3

P: n/a
Invalid User wrote:
While trying to print a none empty list, I accidentaly put an "else"
statement with a "for" instead of "if". Here is what I had:

if ( len(mylist)> 0) :
for x,y in mylist:
print x,y
else:
print "Empty list"

which was supposed to be:

if ( len(mylist)> 0) :
for x,y in mylist:
print x,y
else:
print "Empty list"
Is this to be expected?


Sure. The else branch is executed unless the for terminates
prematurely (via break, return or exception) -- just like the
else branch of a while loop.

Typical use case:

for item in allitems:
if fraboozable(item):
print "first fraboozable item is", item
break
else:
print "Sorry, no item is fraboozable"
Alex

Jul 18 '05 #4

P: n/a

"Mark Jackson" <mj******@alumni.caltech.edu> wrote in message
news:bk**********@news.wrc.xerox.com...
Invalid User <us**@invalid.domain> writes: (This happens to be the *reverse* of what my intuition expects - it
would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and
one must simply remember it.)
There's a certain amount of justification, though. You can
already put whatever amount of logic you need in the if
statement that ends with the break. You don't otherwise
have that ability for normal termination of the sequence.

Frankly, I'd like to see special case syntax for an empty
sequence, but it's not that hard to handle now.

John Roth

--
Mark Jackson - http://www.alumni.caltech.edu/~mjackson
There are no foolish questions and no man becomes a fool
until he has stopped asking questions.
- Charles P. Steinmetz

Jul 18 '05 #5

P: n/a
"John Roth" <ne********@jhrothjr.com> writes:

"Mark Jackson" <mj******@alumni.caltech.edu> wrote in message
news:bk**********@news.wrc.xerox.com...
Invalid User <us**@invalid.domain> writes:

(This happens to be the *reverse* of what my intuition expects - it
would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and
one must simply remember it.)


There's a certain amount of justification, though. You can
already put whatever amount of logic you need in the if
statement that ends with the break. You don't otherwise
have that ability for normal termination of the sequence.


Sure - I wasn't arguing the other meaning was needed, clearly it is
not. It's the use of the keyword "else" which creates the [purely
mental] problem for me.

--
Mark Jackson - http://www.alumni.caltech.edu/~mjackson
There are no foolish questions and no man becomes a fool
until he has stopped asking questions.
- Charles P. Steinmetz
Jul 18 '05 #6

P: n/a

"Mark Jackson" <mj******@alumni.caltech.edu> wrote in message
news:bk**********@news.wrc.xerox.com...
"John Roth" <ne********@jhrothjr.com> writes:

"Mark Jackson" <mj******@alumni.caltech.edu> wrote in message
news:bk**********@news.wrc.xerox.com...
Invalid User <us**@invalid.domain> writes:
(This happens to be the *reverse* of what my intuition expects - it
would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and
one must simply remember it.)


There's a certain amount of justification, though. You can
already put whatever amount of logic you need in the if
statement that ends with the break. You don't otherwise
have that ability for normal termination of the sequence.


Sure - I wasn't arguing the other meaning was needed, clearly it is
not. It's the use of the keyword "else" which creates the [purely
mental] problem for me.


Good point.

John Roth
--
Mark Jackson - http://www.alumni.caltech.edu/~mjackson
There are no foolish questions and no man becomes a fool
until he has stopped asking questions.
- Charles P. Steinmetz

Jul 18 '05 #7

P: n/a
Mark Jackson wrote:
(This happens to be the *reverse* of what my intuition expects - it
would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and
one must simply remember it.)


I'm with you there--the use of "else" here has seemed a bit confusing to me.

The use case that Alex just posted gave me another way to think about it:

for item in allitems:
if fraboozable(item):
print "first fraboozable item is", item
break
else:
print "Sorry, no item is fraboozable"

If I think of the else statement as being related to the if statement inside
the loop, then it makes some sense--the else statement is executed when the
if statement never comes up true. (It's twisted logic, I know, but at least
it helps me keep track of what "else" does here.)

-Mike
Jul 18 '05 #8

P: n/a
In article <vn************@corp.supernews.com>,
Michael Geary <Mi**@DeleteThis.Geary.com> wrote:

The use case that Alex just posted gave me another way to think about it:

for item in allitems:
if fraboozable(item):
print "first fraboozable item is", item
break
else:
print "Sorry, no item is fraboozable"

If I think of the else statement as being related to the if statement
inside the loop, then it makes some sense--the else statement is
executed when the if statement never comes up true. (It's twisted
logic, I know, but at least it helps me keep track of what "else" does
here.)


Maybe it's twisted logic, but it's the only time I've ever used for/else
in real code. It helps if instead of thinking of the else as connected
to the if, you think of the entire for loop as being an extended if
statement.
--
Aahz (aa**@pythoncraft.com) <*> http://www.pythoncraft.com/

"It is easier to optimize correct code than to correct optimized code."
--Bill Harlan
Jul 18 '05 #9

P: n/a

"Michael Geary" <Mi**@DeleteThis.Geary.com> wrote in message
news:vn************@corp.supernews.com...
Mark Jackson wrote:
(This happens to be the *reverse* of what my intuition expects - it would seem more natural if the syntax meant "do this for loop to
completion, else do this extra stuff," but this is the way it is and one must simply remember it.)


I'm with you there--the use of "else" here has seemed a bit

confusing to me.

How I plan to remember now: if the abnormal exit is a return or
exception, then all code end of for block, including any else part, to
the end of the function or try block will be skipped, so else part can
only apply to normal exit.

Terry J. Reedy
Jul 18 '05 #10

P: n/a
On Thu, 25 Sep 2003 11:15:51 -0400, "John Roth"
<ne********@jhrothjr.com> wrote:
Frankly, I'd like to see special case syntax for an empty
sequence, but it's not that hard to handle now.


That is what the 'else' suggests to me - particularly with 'while'
loops. I don't think I've ever needed the existing 'else', but I could
have used a loop-body-not-executed-at-all special case on a number of
occasions

I can see the use an application of 'else', of course - if you use
'break' to end a loop you may need different cleanup and therefore
need to skip the standard cleanup. But if this is an issue I'm
probably already using raise rather than break because it's most
likely an error rather than a normal case.

My guess is that it probably made a lot more sense before exceptions
were added to Python.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #11

P: n/a

"Stephen Horne" <$$$$$$$$$$$$$$$$$@$$$$$$$$$$$$$$$$$$$$.co.uk> wrote in
message news:2c********************************@4ax.com...
On Thu, 25 Sep 2003 11:15:51 -0400, "John Roth"
<ne********@jhrothjr.com> wrote:
Frankly, I'd like to see special case syntax for an empty
sequence, but it's not that hard to handle now.
That is what the 'else' suggests to me - particularly with 'while'
loops. I don't think I've ever needed the existing 'else', but I could
have used a loop-body-not-executed-at-all special case on a number of
occasions

I can see the use an application of 'else', of course - if you use
'break' to end a loop you may need different cleanup and therefore
need to skip the standard cleanup. But if this is an issue I'm
probably already using raise rather than break because it's most
likely an error rather than a normal case.

My guess is that it probably made a lot more sense before exceptions
were added to Python.


I don't see what exceptions have to do with it. There are three
special ending cases: with break, empty sequence and sequence
exhausted. Empty sequence is the only one that isn't handled easily.

I suspect the use of 'else' was simply taking advantage of an
existing keyword, complete with contorted justification of why
that was acceptable.

What I'd like to see is a more general exit clause that also
applies to the while statement. Something like:

on break:
on normal_exit:
on empty_sequence:
on body_not_executed:

"on" would be a keyword, but the other four words would
only be recognized in the context of the "on" statement. It
requires one new keyword, but I think that it's easily
recognizable exactly what it does.

John Roth


--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk

Jul 18 '05 #12

P: n/a
Stephen Horne:
I can see the use an application of 'else', of course - if you use
'break' to end a loop you may need different cleanup and therefore
need to skip the standard cleanup. But if this is an issue I'm
probably already using raise rather than break because it's most
likely an error rather than a normal case.

My guess is that it probably made a lot more sense before exceptions
were added to Python.


I don't agree. Here's an example from my code. The
Match returns an iterator and all the matches have the
same number of atoms, so I want to get that number
if there are any matches or 0 if there are no atoms.

for mb in mcss.Match(mol):
# All matches are equally maximal, so pick one
n = mb.NumAtoms()
break
else:
# No hits
n = 0

This example could be replaced with

n = 0
for mb in mcss.Match(mol):
n = mbNumAtoms()
break

But consider binhex.py, which does

for c in data:
if not x.isspace() and (c<' ' or ord(c) > 0x7f):
break
else:
finfo.Type = 'TEXT'

Without else: this is written as

flg = 0
for c in data:
if not x.isspace() and (c<' ' or ord(c) > 0x7f):
flg = 1
break
if not flg:
finfo.Type = 'TEXT'

which is obviously more cumbersome. But I don't
see how using exceptions make this any nicer.
Here's an example from _strptime.py

for value in to_convert:
if value != '':
break
else:
return ''
... do things with to_convert and return a regexp string

Again, the standard solution without an 'else:' is
to have a flag, which looks uglier.

In my search, I didn't see any examples which were
better done with exceptions -- and since (string) exceptions
existed in the language for a long time (from the start
I would imagine and definitely pre-1.3, which is
about when I started), I find it hard to believe that
your statement reflects what really happened.

Andrew
da***@dalkescientific.com
Jul 18 '05 #13

P: n/a
John Roth:
I don't see what exceptions have to do with it. There are three
special ending cases: with break, empty sequence and sequence
exhausted. Empty sequence is the only one that isn't handled easily.
Could you give an example of when you would actually use an
'empty_sequence' in the real world? It's never been a problem
for me (that I can recall) where that distinction was important.
What I'd like to see is a more general exit clause that also
applies to the while statement. Something like:

on break:
on normal_exit:
on empty_sequence:
on body_not_executed:


Aren't 'empty_sequence' and 'body_not_executed' identical?

Could you give examples using each one?

What about code which uses a return in the block? Is
that counted under 'break'? What about raising an exception?

Andrew
da***@dalkescientific.com
Jul 18 '05 #14

P: n/a
Andrew Dalke (ad****@mindspring.com):
John Roth:
I don't see what exceptions have to do with it. There are three
special ending cases: with break, empty sequence and sequence
exhausted. Empty sequence is the only one that isn't handled easily.


Could you give an example of when you would actually use an
'empty_sequence' in the real world? It's never been a problem
for me (that I can recall) where that distinction was important.


Mmm, I think I agree with Andrew here. In the event that you
want to specifically check whether a sequence is empty wouldn't you
want to simply make that an explicit discovery call ?

eg.

if (len(seq) > 1):
for ...

else:
print 'No items in sequence'

It makes more sense to me to have an explicit discovery of a lack of
items, rather than have a situation where we have the implication that
to loop over an empty sequence is incorrect.

Dave

Jul 18 '05 #15

P: n/a

"Andrew Dalke" <ad****@mindspring.com> wrote in message
news:f%******************@newsread3.news.pas.earth link.net...
John Roth:
I don't see what exceptions have to do with it. There are three
special ending cases: with break, empty sequence and sequence
exhausted. Empty sequence is the only one that isn't handled easily.
Could you give an example of when you would actually use an
'empty_sequence' in the real world? It's never been a problem
for me (that I can recall) where that distinction was important.


I can recall writing a fair number of loops a while back where
knowing that I had an empty sequence was important. More
recently, I have concentrated on making things simply work
if a sequence is empty. I think that's much better programming
practice when you can accomplish it. However, the days when
I thought I was Joe Superprogrammer are long in my past,
and while I don't have a current example, I've got enough
examples from my past that I can't say I could eliminate all
of them.

One example that comes to mind is the case where you
don't want to send a message at all if there are no instances;
for example, if you are doing a build, the case of no failures
is distinct from the case that there were failures. You want to
do two totally different things. Add the wrinkle that it may not
be easy, convenient or possible to test for an empty sequence
first (think some forms of generator) and I think you can come
up with a number of cases.
What I'd like to see is a more general exit clause that also
applies to the while statement. Something like:

on break:
on normal_exit:
on empty_sequence:
on body_not_executed:


Aren't 'empty_sequence' and 'body_not_executed' identical?


Yes, they are. One is more expressive with the for statement,
and the other with the while statement.

Could you give examples using each one?

What about code which uses a return in the block? Is
that counted under 'break'?
I hadn't thought about it. I'd consider it a break.
What about raising an exception?
That should be handled with a try / except block.
I don't see any reason for new syntax.

John Roth

Andrew
da***@dalkescientific.com

Jul 18 '05 #16

P: n/a
On Wed, 01 Oct 2003 03:38:51 GMT, "Andrew Dalke"
<ad****@mindspring.com> wrote:
John Roth:
I don't see what exceptions have to do with it. There are three
special ending cases: with break, empty sequence and sequence
exhausted. Empty sequence is the only one that isn't handled easily.


Could you give an example of when you would actually use an
'empty_sequence' in the real world? It's never been a problem
for me (that I can recall) where that distinction was important.


It's not so much for 'for' loops as for 'while' loops that I've hit
it. Actually, it came up again in some code for the 'primes' thread.

I thought I'd try a tweak of the seive. Whenever I found a new prime,
I'd add a tuple (2*prime, prime) to a queue of non-prime values. It
seemed a nice test of an ordered set class I have written as an
extension.

While searching for new primes, a gap in the queue indicates a new
prime has been found. So the code became...

def Primes (p_Max) :
l_Primes = [2]
l_Rejects = c_Multiset () # tuples of (value, prime factor)
l_Cursor = c_Multiset_Cursor ()
i = 3

l_Rejects.Insert ( (4, 2) ) # prime rejects

l_Cursor.Find_First (l_Rejects)

while i <= p_Max :
if l_Cursor.Key [0] <= i :
while l_Cursor.Key [0] <= i :
l_Value, l_Factor = l_Cursor.Key
l_Value += l_Factor

if l_Value <= p_Max :
l_Rejects.Insert ( (l_Value, l_Factor) )

l_Cursor.Del_Step_Next ()

i += 1

else :
l_Primes.append (i)
l_Rejects.Insert ( (i*2, i) )
i += 1

return l_Primes
The annoyance is the duplication of cases here...

if l_Cursor.Key [0] <= i :
while l_Cursor.Key [0] <= i :

If non-running-the-body-even-once was considered the 'else' special
case, the duplication wouldn't be needed.
As soon as I read Michael Gearys post I remembered the
not-found-anything-in-search application, which does make some sense.

: for item in allitems:
: if fraboozable(item):
: print "first fraboozable item is", item
: break
: else:
: print "Sorry, no item is fraboozable"
:

Personally I tend to avoid 'break' as far as reasonable, seeing it as
unstructured - a kind of goto. As I wouldn't usually use break that
way, I equally wouldn't use else that way either.

In this case, I would make use of one of my first generators...

def linearsearch (p_Pred, p_Seq) :
i = 0
for j in p_Seq :
if p_Pred (j) :
yield (i, j)
i += 1

Giving code like...

search = linearsearch (fraboozable, allitems)

try :
index, value = search.next ()
print "first fraboozable item is", index

except StopIteration :
print "Sorry, no item is fraboozable"
This may seem odd at first, but it has a major advantage - you can
easily continue the search from where you left off.

BTW - you can get the same effect with itertools.ifilter and
enumerate, but it's a bit of a pain.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #17

P: n/a
Stephen Horne wrote:
...
As soon as I read Michael Gearys post I remembered the
not-found-anything-in-search application, which does make some sense.

: for item in allitems:
: if fraboozable(item):
: print "first fraboozable item is", item
: break
: else:
: print "Sorry, no item is fraboozable"

Personally I tend to avoid 'break' as far as reasonable, seeing it as
Me too: it's just that I think that most attempts to avoid break are
totally unreasonable, so I don't do them:-).
unstructured - a kind of goto. As I wouldn't usually use break that
way, I equally wouldn't use else that way either.
break is a "structured goto", no different in that respect from if/else,
while, continue. Or the explicit try/except StopIteration that you
appear to prefer so intensely, for that matter.
In this case, I would make use of one of my first generators...
So, if "fraboozable(item)" stood for, say, "item**3 > 33", would
you use lambda or a named function in order to pass the "predicate"
to your generator? I think either case is far less readable than just
expressing the condition inline (which is part of why list comprehensions
beat map and filter by a mile -- they're all expressed inline).
This may seem odd at first, but it has a major advantage - you can
easily continue the search from where you left off.
If I needed that, I would simply make an explicit iterator for the
items sequence, of course:

itemsiter = iter(allitems)
for item in itemsiter:
if fraboozable(item):
# and the rest as above

thus making this loop just as "continuable where it left off" as
a generator would be. Moreover, if what I need after the first
fraboozable item is the first succeeding bambalable item, I need
no major restructuring -- I'll just use bambalable(item) in the
second "continuing" loop.
BTW - you can get the same effect with itertools.ifilter and
enumerate, but it's a bit of a pain.


So we disagree on this sub-topic too -- I think composing itertools
functions and such builtins as enumerate is more often a veritable
pleasure, far more fun than writing generators more often than not.
In this particular case, since the index within the sequence is not
of interest, itertools.ifilter seems clearly preferable, in particular.

But simple for loops, _with_ their due complement of break and else
as needed, are often more practical, anyway. Often a for loop WILL in
fact run on the iterator returned by some sophisticated generator
(whether that's freshly coded, or composed from itertools bricks),
but ALSO add the small extra of a useful break just where it does
most good.

For example, consider checking whether a sequence is sorted or not
(ignoring for simplicity empty sequences):

seqiter = iter(seq)
lastone = seqiter.next()
for item in seqiter:
if compare_badly(item, lastone):
print "unsorted"
break
lastone = item
else:
print "sorted"

where often but not always compare_badly will be > . Writing a very
special-case generator just for this use would go, let's see, how?

def check_sorted(aniter, compare_badly=None):
if compare_badly is None:
def compare_badly(x, y): return x>y
seqiter = iter(seq)
lastone = seqiter.next()
for item in seqiter:
yield compare_badly(item, lastone)
lastone = item

??? Or with a less-special-cased one such as:

def window_by_two(aniter):
seqiter = iter(seq)
lastone = seqiter.next()
for item in seqiter:
yield item, lastone
lastone = item

??? At least the latter makes sense, since it encapsulates a useful
general concept, "windowing by 2" of a sequence. But isn't the "one
obvious way" to use it...:

for item, lastone in window_by_two(seq):
if compare_badly(item, lastone):
print "unsorted"
break
else:
print "sorted"

??? Well, I guess it is only for those of us that don't suffer from
allergy to 'break' -- if one did, then maybe

badpairs = itertools.ifilter(lambda x: compare_badly(*x),
window_by_two(seq))
try:
badpairs.next()
except StopIteration:
print "sorted"
else:
print "unsorted"

might prove "more obvious" (???-).
Alex

Jul 18 '05 #18

P: n/a
On Wed, 01 Oct 2003 18:10:40 GMT, Alex Martelli <al***@aleax.it>
wrote:
break is a "structured goto", no different in that respect from if/else,
while, continue. Or the explicit try/except StopIteration that you
appear to prefer so intensely, for that matter.
Basically, to me, a key thing about the term 'block structured' is
about a clear and simple layout and a separation of 'layers'. The body
contained within a block structure should be distinct from that
structure - there shouldn't be bits of the block structure hidden
inside the body. If 'break' is a part of the loop, it shouldn't be
buried inside the body - it should be associated with the loop.

It's a similar principle to encapsulation, in a way.

That is the 'why' for the PEP315 discussion a little while back -
though as I said then, I'm not that much against the existing 'if x :
break' - I mainly don't like the existing proposal that means 'while x
:' may get a new and potentially confusing meaning, so wanted to
suggest an alternate syntax if some change is definitely happening.
An exception is subtly different. It's certainly a matter of
pragmatics - a raise is certainly unstructured in the sense I
described above - but that is its whole reason for existence.

When you see a loop, at least nine times out of ten it will not have a
break or a continue. The expectation, therefore, is that these hidden
exit points do not exist. When you see a try block with an exception
handler, that is a pretty strong hint that the code in the try block
may raise that exception - no matter how well hidden the raise may be.

Furthermore, exceptions are named - another useful hint to what is
going on.
Actually, 'break' can be prone to a fairly common maintenance error.
If you start with this...

while x :
...
if y :
break;
...

and add an inner loop, failing to notice the hidden break, like
this...

while x :
...
while z :
...
if y : break;
...
...

....that code will fail as the break now only exits the inner loop, but
if you raise an exception, the code starts as...

try :
while x :
...
if y : raise blah
...
except blah :
...

and becomes...

try :
while x :
...
while z :
...
if y : raise blah
...
...
except blah :
...

The key advantage being that the exception still exits the outer loop
as well as the inner loop, so the result is still as intended even if
the maintainer didn't notice the raise statement.

Of course this is often overkill, which is part of why break is
sometimes reasonable.
In this case, I would make use of one of my first generators...


So, if "fraboozable(item)" stood for, say, "item**3 > 33", would
you use lambda or a named function in order to pass the "predicate"
to your generator? I think either case is far less readable than just
expressing the condition inline (which is part of why list comprehensions
beat map and filter by a mile -- they're all expressed inline).


I tend to agree with you. I will use lambda without too much
hesitation, but at the very least I wish it had a better name.

Of course you can often define a named function just before it is
needed. For instance...

def example :
...
def predicate (x) :
return some-function-of (x)

a = itertools.ifilter (predicate, seq)
Inline has definite advantages, and I certainly prefer list
comprehensions to combining filter and map (and lets not forget that
list comprehensions have some additional tricks up their sleeves) but
neither a lambda nor a named function is really a disaster.
BTW - you can get the same effect with itertools.ifilter and
enumerate, but it's a bit of a pain.


So we disagree on this sub-topic too -- I think composing itertools
functions and such builtins as enumerate is more often a veritable
pleasure, far more fun than writing generators more often than not.
In this particular case, since the index within the sequence is not
of interest, itertools.ifilter seems clearly preferable, in particular.


I made a stupid mistake there - I thought the index was relevant,
which is why I mentioned enumerate and gave my own generator. I guess
I've got indices on the brain after the PEP288 and PEP322 discussions.

If the enumerate was necessary, the expression needs the ifilter, the
enumerate, and a lambda. It is the combination that can get confusing,
especially when the resulting expression needs two or more lines.
seqiter = iter(seq)
lastone = seqiter.next()
for item in seqiter:
if compare_badly(item, lastone):
print "unsorted"
break
lastone = item
else:
print "sorted"


This is extremely compelling, I have to admit - loops that iterates
through sliding window positions (and thus for all items but one, or
whatever) can be a pain at times, and this combination of iterator and
for loop gives a very nice structure for it.

I never thought of this idea because of my historic understanding of
'for' as looping through the whole sequence. Thanks for helping me
take off those blinkers.

I'd still be tempted to say that 'if you expect it to be sorted, then
unsorted is an error' though and raise an exception when the unsorted
pair is found...

try:
seqiter = iter(seq)
lastone = seqiter.next()
for item in seqiter:
if compare_badly(item, lastone): raise unsorted
lastone = item

print "sorted"

catch unsorted :
print "unsorted"
But it is just a personal preference of course, and has no advantage
at all in a trivial case like this.
BTW...

I didn't say I'd use a generator for everything - I said "In this
case" (and was wrong because I misread the case - as you say, I only
needed itertools.ifilter).

I also do not have an allergy to break - as I said, I "I tend to avoid
'break' as far as reasonable" but as you said there are times when it
is unreasonable to avoid it.

The biggest rule I have for 'break' is that the loop body must be
small enough that the break is unmissable. If the loop is that simple,
however, there is usually a simple way to handle the requirement that
doesn't need break.

If there is a simple alternative I will tend to prefer it over using
break. Therefore I rarely use break, and therefore I have never (as
far as I remember) used else on a loop. That is all I am saying. I'm
not a fundamentalist by any means.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #19

P: n/a
On Wed, 01 Oct 2003 03:31:10 GMT, "Andrew Dalke"
<ad****@mindspring.com> wrote:
In my search, I didn't see any examples which were
better done with exceptions -- and since (string) exceptions
existed in the language for a long time (from the start
I would imagine and definitely pre-1.3, which is
about when I started), I find it hard to believe that
your statement reflects what really happened.


You are quite right - I think I mentioned already in another post that
I'd completely forgotten the break-on-found idiom until I read Michael
Gearys post (I don't always read a thread fully before I reply to
stuff).

I still think that exception-based approaches are far from painful for
this kind of stuff. However, with your example from binhex.py...

for c in data:
if not c.isspace() and (c<' ' or ord(c) > 0x7f):
break
else:
finfo.Type = 'TEXT'

The cleanest way to eliminate the 'break' and 'else' is probably as
follows...

try:
c = data.next ()
while c.isspace() or (c<' ' or ord(c) > 0x7f) : c = data.next ()
except StopIteration :
finfo.Type = 'TEXT'

Or possibly...

try :
ifilter (lambda c : c in string.printable, data).next ()
except StopIteration :
finfo.Type = 'TEXT'

But these approaches both have a major failing - they don't express
the intention well.

Actually, there is a very clean and expressive approach that I'd use
if I had access to my own library stuff...

if mylib.exists (lambda c : c in string.printable, data) :
finfo.Type = 'TEXT'

with, in 'mylib'...

def exists (pred, seq) :
for i in seq :
if pred(i) : return True
return False

....which is, of course, cheating as that return is just as
unstructured as a break - but I don't mind cheating too much when it
is localised in a trivial library function.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #20

P: n/a
In article <ru********************************@4ax.com>,
Stephen Horne <$$$$$$$$$$$$$$$$$@$$$$$$$$$$$$$$$$$$$$.co.uk> wrote:
I still think that exception-based approaches are far from painful for
this kind of stuff. However, with your example from binhex.py...

for c in data:
if not c.isspace() and (c<' ' or ord(c) > 0x7f):
break
else:
finfo.Type = 'TEXT' .... Actually, there is a very clean and expressive approach that I'd use
if I had access to my own library stuff...

if mylib.exists (lambda c : c in string.printable, data) :
finfo.Type = 'TEXT'

with, in 'mylib'...

def exists (pred, seq) :
for i in seq :
if pred(i) : return True
return False

...which is, of course, cheating as that return is just as
unstructured as a break - but I don't mind cheating too much when it
is localised in a trivial library function.


Haven't you inverted the logic here?
You want a universal quantifier, not an existential one.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science
Jul 18 '05 #21

P: n/a
On Wed, 01 Oct 2003 20:10:03 -0700, David Eppstein
<ep******@ics.uci.edu> wrote:
Haven't you inverted the logic here?
You want a universal quantifier, not an existential one.


Yes, absolutely correct.

I did some hacking around with different ways of representing this.
The condition got inverted a few times. The final version was derived
from something like this...

if not mylib.exists (lambda c : c not in string.printable, data) :
finfo.Type = 'TEXT'

And I forgot to switch the quantifier when I inverted the logic for
some bizarre reason. I guess that's what happens when you spend too
much time obsessing over a piece of code - the longer you spend
fussing over it the greater the odds of making a stupid mistake, and
the less likely you are to spot it :-(

So yes, the debugged version is...

if mylib.always (lambda c : c in string.printable, data) :
finfo.Type = 'TEXT'

with...

def always (pred, seq) :
for i in seq :
if not pred(i) : return False
return True
While these 'every' and 'always' functions are trivial, they are also
pretty useful and obviously based on the common discrete maths
notation so not unique to me.

Could some simple functions like this have a place in the library
somewhere?
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #22

P: n/a
Stephen Horne wrote:
...
def always (pred, seq) :
for i in seq :
if not pred(i) : return False
return True

While these 'every' and 'always' functions are trivial, they are also
pretty useful and obviously based on the common discrete maths
notation so not unique to me.

Could some simple functions like this have a place in the library
somewhere?


They might, *EXCEPT* that "passing a callable" is out of fashion, and
out of favour, in the BDFL's current opinion -- and for good reasons,
too, although they MIGHT change in the future. The BDFL is on record
as regretting ever having accepted lambda into the language, and map,
filter and reduce into the languages' builtins; 3.0 (maybe in 2-3 years)
will be mostly about *simplification*, i.e. *removal* of some of the
"more than one way" things that have accreted over the years, and in
that release lambda and the 'functional'-ish built-ins are quite likely
to go (the latter might get moved to some backwards-compat module); such
new language features as list comprehensions have among their major pluses
the ability to NOT "pass callables" but rather write code in-line.

So I strongly doubt that any new construct *ENCOURAGING* people to
write "if always(lambda x: x>23, myseq):" and the like stands any
substantial chance of getting into the language and built-ins. I
could be wrong, of course; channeling Guido is Tim Peters' job, not
mine. But if you could figure out a GOOD Pythonic way to pass an
anonymous codeblock into a function, as e.g. Ruby and Smalltalk do
so naturally -- particularly a good SYNTAX, that's the hardest part --
THEN you might stand a good chance of "revolutionizing" Python, at
least at 3.0 time. The ability to code predicates inline would be
key, here. Neither:
if always(lambda x: x>23, myseq):
...
nor:
def gt23(x): return x>23
if always(gt23, myseq):
...
are currently considered GOOD. What might be? I dunno. Ruby's
concepts (that the block, if present, always goes AFTER the function;
only one block can be there, at most; ...) might be acceptable limits
if they helped a good syntax; lambda's current limit (no statements,
just an expression -- and all the distortions THAT encourages) is
not acceptable.

E.g., suppose (and I doubt it IS so in reality:-) that making 'def'
do double duty was deemed acceptable; 'def' would denote a statement
when used like today, but it might also be an _expression_ instead,
if and only if used as the last actual-argument to a function, a la:

if always(myseq, def isgood(x): return x>23):
...

or:

if always(myseq, def memoized_predicate(x):
try: return _memo[x]
except KeyError:
_memo[x] = lots_of_computations(x)
return _memo[x]
):
...

THEN, _IF_ the BDFL liked this specific syntax (and, to repeat,
I strongly doubt he would!!!), you MIGHT well get your 'always',
'exists', etc etc -- and many other neat ideas currently held
in limbo because of the "passing a callable" issue might also
get "unblocked". Among the problems is, there is no precedent
for an _expression_ being whitespace/indentation sensitive, yet
something like that would be indispensable for any such idea...
Alex

Jul 18 '05 #23

P: n/a
On Thu, 02 Oct 2003 09:26:43 GMT, Alex Martelli <al***@aleax.it>
wrote:
They might, *EXCEPT* that "passing a callable" is out of fashion, and
out of favour, in the BDFL's current opinion -- and for good reasons,
too, although they MIGHT change in the future.


I agree mostly. At present, first-class functions are very powerful
tools, but they certainly have some drawbacks.

The trouble, as you said, is the syntax. At present, the most natural
syntax happens in list comprehensions - where the language grammar
isolates the 'code block'. It's hard to think of a good syntax which
(1) doesn't recreate lambda to explicitly mark out the 'code block',
and (2) can exist within Pythons existing dynamic model.

:-(
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #24

This discussion thread is closed

Replies have been disabled for this discussion.