re-entering in the normal flow after an exception is raised
Shai Berger
shai at platonix.com
Thu Sep 30 03:11:30 EDT 2004
It's called "restarts" in Common Lisp. The basic idea, if I got it right, is
that you keep a global mapping from exception types to functions, and
whenever an exception is raised by the code, if the mapping has an entry for
it, the function is called instead. Lisp makes it easy to manage the mapping
in concert with program flow (that is, adding an entry works much like adding
an exception handler in Python). It is as if you could write,
# PSEUDO-CODE
def ignoreException(exc): continue
try:
func()
restart NotSeriousException:
ignoreException
Now, notice that the code under the restart clause returns a function; this is
the function that will be called instead of raising the exception, within
do_this, and whatever it returns is returned instead of continuing the
do_this code.
Common Lisp goes further, and uses this mechanism for error handling that is
more flexible than is usually achieved with Exceptions, by doing something
that is essentially like throwing exceptions from the functions used for
restarts; this means you can have
class SomeError(Exception): pass
class RecoveryStrategy1(Exception): pass
class RecoveryStrategy2(Exception): pass
def innermost():
raise SomeError()
def medium():
try:
innermost()
except RecoveryStrategy1:
do_this()
except RecoveryStrategy2:
do_that()
def outer():
try:
medium()
restart SomeError:
def f(exc): raise RecoveryStrategy1()
f
Which means that medium defines and implements the recovery strategies, but
only outer chooses among them.
Now, if you don't need the dynamic-try-like feature, I guess you could write
something like this (untested):
# A special method for raising exceptions
def raise_(exc):
if exc.__class__.hasattr('restart_func'):
return exc.__class__.restart_func(exc)
else:
raise exc
# Modified from the original to use the new raise_() instead of raise
def do_this():
raise_(NotSeriousException())
def do_that():
pass
def do_this_and_that():
do_this()
do_that()
def ignore_exception(exc): pass
def call_do_this_and_that():
#instead of your "try'
NotSeriousException.restart_func = ignore_exception
do_this_and_that()
On second thought, this is a lot like Bengt's suggestion of complain().
BTW: We could implement behavior that mimics Common Lisp more closely, if we
had dicts we could play with on frame objects. We could do plenty of other
useful stuff, too, but that's for another post.
More information about the Python-list
mailing list