Working around a lack of 'goto' in python
Roy Smith
roy at panix.com
Tue Mar 9 16:05:06 EST 2004
Joe Mason <joe at notcharles.ca> wrote:
> In article <roy-F325DF.12255009032004 at reader2.panix.com>, Roy Smith wrote:
> > OK, I'll bite. What's wrong with exceptions for breaking out of deeply
> > nested loops?
>
> Philosophically, the termination condition of a loop isn't an
> exceptional circumstance.
The normal flow of control is when you fall out the bottom of the loop
when your control test goes false. Breaking out of the middle is indeed
an exceptional circumstance; it is an exception to the normal flow of
control. People tend to think of exceptions as errors, but they don't
have to be.
Now, to be fair, imagine a construct like this:
try:
for i in range (iMax):
for j in range (jMax):
for k in range (kMax):
if thisIsIt (i, j, k):
raise IFoundIt
print "it's not there"
except IFoundIt:
print "yes it is"
Presumably the expectation is that the thing you're looking for will
exist somewhere in the i,j,k coordinate space. Falling out the bottom
of the loop is now the error condition. I think this is what you were
getting at, and I agree that this turns the whole concept of an
exception on its ear. The example above is one where I think factoring
it out into a function makes the most sense:
def whereIsTheThing ():
for i in range (iMax):
for j in range (jMax):
for k in range (kMax):
if thisIsIt (i, j, k):
return (i, j, k)
raise ItsNotThere
> Practically, exceptions are overkill. Using named break (or faking it
> with goto) is "static multi-level exit", while an exception is dynamic.
> It takes more overhead at runtime
That's certainly true in C++. In complied/static languages like C++,
there can be a significant speed difference between things that can be
done at compile time and things that need to be done at run time (like
constructing exception objects).
In Python, the cost of using exceptions is way less. I just tried a
little test, timing a bunch of breaks vs raises to get out of an inner
loop (code listing below). My timing results were:
count = 10000, the break way took 7.349000 seconds
count = 10000, the exception way took 8.121592 seconds
Yeah, the exceptions were slower, but only 10% slower, and that's for a
loop that did essentially no useful work, so it's all overhead. The
difference would be smaller if the loop did anything real. I'm not
likely to let such a small change in execution time drive my code
design. If I was worried about such small speed gains, I wouldn't be
writing in Python.
I would try repeating this example in C++, but the thought of how many
lines of code I'd have to write to do it has convinced me that it should
be left as "an excercise for the reader" :-)
> and if you don't catch it right it
> can escape up the call stack.
Well, yeah, but the answer to that is you catch it. In fact, that's one
of the nice things about exceptions. If you don't catch it correctly,
you find out about it fast. If you mis-code a goto or break label, you
just quietly execute the wrong code.
> A more pragmatic argument is that, for C++,
[...]
> // declare an EndLoopException class, which I forget how to do because
> // I haven't used C++ exceptions in ages
I think what you've demonstrated here is not so much that exceptions are
a bad thing, but that C++'s implementation of exceptions (like most
things in C++) is overly complicated. I find it interesting that many
people who come from a C++ background (especially those who migrated
from C) tend to dislike exceptions. It must have been something in the
water when they were growing up :-)
--------------
#!/usr/bin/env python
import time
class Break (Exception):
pass
x = 10000
t0 = time.time ()
count = 0
for i in range (x):
for j in range (x):
break
count += 1
t1 = time.time ()
print "count = %d, the break way took %f seconds" % (count, t1 - t0)
t0 = time.time ()
count = 0
for i in range (x):
try:
for j in range (x):
raise Break
except Break:
pass
count += 1
t1 = time.time ()
print "count = %d, the exception way took %f seconds" % (count, t1 - t0)
More information about the Python-list
mailing list