"for" with "else"?

Stephen Horne $$$$$$$$$$$$$$$$$ at $$$$$$$$$$$$$$$$$$$$.co.uk
Wed Oct 1 13:04:37 EDT 2003


On Wed, 01 Oct 2003 03:38:51 GMT, "Andrew Dalke"
<adalke at 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




More information about the Python-list mailing list