6.5. Custom Exception Classes
You can subclass any of the standard exception classes in order to define your own exception class. Often, such a subclass adds nothing more than a docstring:
class InvalidAttribute(AttributeError): "Used to indicate attributes that could never be valid"
As covered in "The pass Statement" on page 69, you don't need a pass statement to make up the body of this class; the docstring (which you should always write) is quite sufficient to keep Python happy. Best style for such "empty" classes, just like for "empty" functions, is to have a docstring and no pass.
Given the semantics of try/except, raising a custom exception class such as InvalidAttribute is almost the same as raising its standard exception superclass, AttributeError. Any except clause that can handle AttributeError can handle InvalidAttribute just as well. In addition, client code that knows specifically about your InvalidAttribute custom exception class can handle it specifically, without having to handle all other cases of AttributeError if it is not prepared for those. For example:
class SomeFunkyClass(object): "much hypothetical functionality snipped" def _ _getattr_ _(self, name): "this _ _getattr_ _ only clarifies the kind of attribute error" if name.startswith('_'): raise InvalidAttribute, "Unknown private attribute "+name else: raise AttributeError, "Unknown attribute "+name
Now client code can be more selective in its handlers. For example:
s = SomeFunkyClass( ) try: value = getattr(s, thename) except InvalidAttribute, err: warnings.warn(str(err)) value = None # other cases of AttributeError just propagate, as they're unexpected
It's an excellent idea to define, and raise, custom exception classes in your modules rather than plain standard exceptions: by using custom exceptions, you make it easier for all callers of your module's code to handle exceptions that come from your module separately from others.
A special case of custom exception class that you may sometimes find useful is one that wraps another exception and adds further information. To gather information about a pending exception, you can use the exc_info function from module sys (covered in exc_info on page 168). Given this, your custom exception class could be defined as follows:
import sys class CustomException(Exception): "Wrap arbitrary pending exception, if any, in addition to other info" def _ _init_ _(self, *args): Exception._ _init_ _(self, *args) self.wrapped_exc = sys.exc_info( )
You would then typically use this class in a wrapper function such as:
def call_wrapped(callable, *args, **kwds): try: return callable(*args, **kwds) except: raise CustomException, "Wrapped function propagated exception"
6.5.1. Custom Exceptions and Multiple Inheritance
A particularly effective approach to custom exceptions (one that is, however, not often used in Python practice) is to multiply inherit exception classes from your module's special custom exception class and a standard exception class, as in the following snippet:
class CustomAttributeError(CustomException, AttributeError): pass
Now when your code raises an instance of CustomAttributeError, that exception can be caught by calling code that's designed to catch all cases of AttributeError as well as by code that's designed to catch all exceptions raised by your module. Whenever you must decide whether to raise a specific standard exception, such as AttributeError, or a custom exception class you define in your module, consider this multiple-inheritance approach, which gives you the best of both worlds. Make sure you clearly document this aspect of your module; since the technique I just described is not widely used, users of your module will not expect it unless you clearly and explicitly document what you are doing.
6.5.2. Other Exceptions Used in the Standard Library
Many modules in Python's standard library define their own exception classes, which are equivalent to the custom exception classes that your own modules can define. Typically, all functions in such standard library modules may raise exception of such classes, in addition to exceptions in the standard hierarchy covered in "Standard Exception Classes" on page 130. For example, module socket supplies class socket.error, which is directly derived from built-in class Exception, and several subclasses of error named sslerror, timeout, gaierror, and herror; all functions and methods in module socket, besides standard exceptions, may raise exceptions of class socket.error and subclasses thereof. I cover the main cases of such exception classes, in the rest of this book, in correspondence to the standard library modules that supply them.