subclassing Exceptions
Tom Bryan
tbryan at python.net
Sat Jul 21 22:46:25 EDT 2001
Sheila King wrote:
> On Sun, 22 Jul 2001 00:51:31 -0500, "Volucris" <volucris at hotmail.com>
> wrote in comp.lang.python in article
> <3b5a69a3$0$320$6e49188b at news.goldengate.net>:
>
> :If all you want is your own exception (nothing fancy), all you need is a
> :class:
> :
> :class SpamException:
> : pass
>
> OK, interesting. I didn't realize you could make an exception without
> subclassing it. So, I tried this script:
Neither did I, but you probably don't want to do that.
One reason to subclass from a common Exception base class is so
that exceptions can be caught based on inheritence. Also, since
there's a common exception base class, all exceptions have common
behavior that you'd have to recode if you didn't subclass.
> Hmm...I just tried a little experiment in the interactive shell to see
> if I could confirm/deny my above theory, and it gave me surprising
> results that I do not understand, and which seem to indicate no
> difference between deriving it from an Exception class or not.
Consider:
----- test1.py -----
class SpamException:
pass
try:
while (1):
inputstring = raw_input("Enter any string, except 'spam': ")
if inputstring == "spam":
raise SpamException
# Catch *all* exceptions...
# at least those that subclass Exception like they should. :-)
except Exception, data:
print "Ahhh! ", data
-----------------
If I run this, the except block is unable to catch SpamException,
although it looks like I should be catching all exceptions since I'm
catching the base class of all exceptions:
Enter any string, except 'spam': spam
Traceback (most recent call last):
File "test_exception.py", line 11, in ?
raise SpamException
__main__.SpamException: <__main__.SpamException instance at 0x80d6cb4>
----- test2.py -----
class SpamException(Exception):
pass
try:
while (1):
inputstring = raw_input("Enter any string, except 'spam': ")
if inputstring == "spam":
raise SpamException( 'User typed "spam."' )
# Catch *all* exceptions...
# at least those that subclass Exception like they should. :-)
except Exception, data:
print "Ahhh! ", data
----------------
Since I sublcass Exception, the except block will be able to catch my
exception, and the SpamException automatically gets a constructor
that takes an error message as an argument. See:
Enter any string, except 'spam': spam
Ahhh! User typed "spam."
> Well, I am interested in further enlightenment on this topic...?
I believe that the intent is for all exception classes to subclass from
Exception or one of its sublcasses. I think that a common idiom is for
a module to declare its own base exception class. Then, it can declare
many subclasses of *that* Exception subclass to use internally. People
using the module can simply catch the base FooException unless they
have a good reason to get more specific. Basically, they called code
in your module, and it blew up. Often, that's as much as they can say,
and the error message attached to the exception *should be* enlightening
enough to troubleshoot the problem.
For example,
class StackException( Exception ):
pass
class EmptyStackException( StackException ):
pass
class StackOverflowException( StackException ):
pass
class Stack:
"""An implementation of the Stack data structure
that supports a maximum stack stize. """
def __init__( self, maxSize=None ):
try:
self.stack = []
self.max = int( maxSize )
except ValueError:
#value error is thrown when maxSize isn't an integer
raise StackException( "Illegal value for Stack's maximum size: %s." % maxSize )
def push( self, data ):
if self.max != None and len(self.stack) == self.max:
raise StackOverflowException( "Stack already at maximum size %d" % self.max )
self.stack.append( data )
def pop( self ):
if len( self.stack ) == 0:
raise EmptyStackException( "Cannot pop from an empty stack" )
self.stack, data = self.stack[:-1], self.stack[-1]
return data
def peek( self ):
if len( self.stack ) == 0:
raise EmptyStackException( "Cannot peek at an empty stack" )
return self.stack[ -1 ]
if __name__ == '__main__':
# Note that our code can simply catch the StackException base class
try:
aStack = Stack( 'hi' )
except StackException, data:
print "Exception for Stack('hi'):", data
try:
aStack = Stack( 2 )
print aStack.peek()
except StackException, data:
print "Exception for aStack.peek():", data
try:
print aStack.pop()
except StackException, data:
print "Exception for aStack.pop():", data
try:
aStack.push( 'one' )
aStack.push( 'two' )
aStack.push( 'three' )
except StackException, data:
print "Exception for aStack.push('three'):", data
Of course, this advice might be slightly off. Python's exception stuff looks
a lot like the Java exception stuff, and I've done a lot more Java.
Exception-"too-many-languages"-ly yours
---Tom
More information about the Python-list
mailing list