Breaking out of nested loops

Steven Majewski sdm7g at Virginia.EDU
Sat Jan 12 20:18:19 EST 2002


On Sat, 12 Jan 2002, Ulf Magnusson wrote:

> "Peter Hansen" <peter at engcorp.com> wrote in message
> >
> > > Exceptions should only be used for real exceptions when something
> > > is wrong, not to change the flow of the program.
> >
> > The word "exception" simply refers to something other than the
> > normal case.  There's really nothing wrong with using it for
> > *exceptional* conditions, which obviously is the case with most
> > magic_breaks that get you out of a deeply nested loop.  There
> > are sometimes concerns with performance (using exceptions can
> > be much slower than simpler things in some languages) but
> > generally I think this is probably the best way.
> >
> > > But this is of course my humble opinion
> > >
> > > Do I make any sence?
> >
> > This is just _my_ humble opinion, but I think we both make sense... :)
>
> Yes, I agree with you Peter, but I guess it is more a question of religion
> than
> what is right or wrong here.
> I for one, am really restrictive using exceptions in non "failure"
> situations

 I don't think it's a matter of religion. It's a matter of language.
In some other languages, 'non failure' mode exceptions may be unusual,
but it's the normal idiom in Python. This has been discussed before
several times. It's not a matter of opinion: Peter's objectively
correct. Python's for loop implementation has used exceptions to
break out of the loop. The exact implementation has changed with
the addition of iterators, but before StopIteration, it was another
exception. You might object that that usage is 'under the hood' ,
however, there are cases where you may likely use an explicit
'raise StopIteration' in your code to interact with that 'under
the hood' protocol.
 Part of the idea behind Exceptions as classes was to make it
easier to classify different sorts of exceptions: failure exceptions
vs. control exceptions for one example.



However, after trying out an example with multilevel nesting,
I see that, although it works fine, it does appear a bit awkward
in Python:

# --------------------------
class Break1(Exception): pass
class Break2(Exception): pass
class Break3(Exception): pass

from random import randint
tab = '  '

def btest():
  try:
    while 1:
      print 'While1'
      try: ##
        while 2:
          print tab,'While2'
          try:
            while 3:
              print tab*2,'While3'
              for i in range(30):
                 r = randint(0,6)
                 print tab*3,'r=',r
                 if r == 1: raise Break1
                 elif r == 2: raise Break2
                 elif r == 3: raise Break3
          except Break3:
            print tab*2,Break3
      except Break2:
        print tab,Break2
  except Break1:
    print Break1

for test in (1,2,3):
	print 'test',test
	btest()
#-------------------------

I admit, it's not simple to follow the control thru all of the
extra try/excepts and indentation. However, since the exceptions
do work across function boundaries, if you break it up into
nested functions (that then still raise exceptions) it's easier
to follow.

But then, I'm not sure that adding something like named blocks would
be any more readable. You would still need an extra level of nesting,
but the lack of an 'except' would make it more difficult to spot
the point it breaks out to. And having to count levels for a syntax
like "break 3" would be even worse.

( Although, I find named blocks in Lisp OK, but you're more free
  to use the indentation to make the flow more clear. )

That conclusion tends to reinforce my initial reaction to these
proposals: that the 'problem' is really that deeply nested loops
in a single procedure is the real 'design error' , not any particular
syntax. Sometimes it can't be avoided, but I haven't seen a proposal
for new syntax that is any easier to read than the example above.


-- Steve Majewski






More information about the Python-list mailing list