[Tutor] while else, for else

Magnus Lycka magnus@thinkware.se
Tue, 15 Oct 2002 12:07:00 +0200


At 09:30 2002-10-14 -0400, Blake.Garretson@dana.com wrote:
>I have been using Python for 3+ years now, and I have yet to see regular
>use of the "while else" or "for else" constructs.  I personally *never* use
>them, and unless I haven't read enough source code from other people, I
>haven't seen evidence that anybody else uses them very often either.

I use them now and then. It's a bit like
try...except in cases where you know that
you should break out of the loop if all
goes as expected:

Like this excerpt from a large program:

         for c in condIndex.findByMainName(name):
             if c.system =3D=3D system:
                 imp =3D c
                 break
         else:
             noObject =3D NothingObject(system)
             imp =3D Condition(name, 'C', noObject, system, '')

If I find a Condition 'c' with a given name belonging
to a given system, I use that. Otherwise, I make a new
Condition (with a dummy Object).

Without for...else I would have done:

         imp =3D None
         for c in condIndex.findByMainName(name):
             if c.system =3D=3D system:
                 imp =3D c
                 break
         if imp is None:
             noObject =3D NothingObject(system)
             imp =3D Condition(name, 'C', noObject, system, '')

Just one more line of code, but once you get used
to the concept of for/while...else, the first version
is much easier to read. It reads more like prose, with
a better flow and less surprise. Why should I do 'imp=3DNone'
if I never really wan't imp to be None? Besides, I assume
this will be more bytecode. The if-test has to be made.
for/while...else might provide some performance improvement.

A little further down:

         row =3D 0
         for f in self.getCatalog(Function):
             if f =3D=3D function and self.getProcessMatrixRow(f, row):
                 # We found a row to copy
                 break
             row +=3D 1
         else:
             return
         procRow =3D self.getProcessMatrix()[row]
         for col in range(len(procRow)):
             code =3D procRow[col][0]
             self.changeProcessMatrix(row, col, code)

Since the function ended here, it might as well have been:

         row =3D 0
         for f in self.getCatalog(Function):
             if f =3D=3D function and self.getProcessMatrixRow(f, row):
                 # We found a row to copy
                 procRow =3D self.getProcessMatrix()[row]
                 for col in range(len(procRow)):
                     code =3D procRow[col][0]
                     self.changeProcessMatrix(row, col, code)
                     return
             row +=3D 1

Perhaps the second is better? It's just a matter
of style. I found it simpler when I wrote it to see
it as a two step process: First find the row, and
then process it. The first version emphasizes this
separation, and also leads to less indentation. Not
a huge win in this case, but I guess I just wrote it
like I did because I thought of it like two separate
steps. Also, the second versions seems to suggest
that there is a nested loop here, and that's not
really the case, since the inner loop will only run
once.


--=20
Magnus Lyck=E5, Thinkware AB
=C4lvans v=E4g 99, SE-907 50 UME=C5
tel: 070-582 80 65, fax: 070-612 80 65
http://www.thinkware.se/  mailto:magnus@thinkware.se