Define Your Own Exception Classes
TL;DR
- Defining your own exception types will state your code’s intent more clearly and make it easier to debug.
- Derive your custom exceptions from Python’s built-in Exception class or from more specific exception classes like ValueError or KeyError.
- You can use inheritance to define logically grouped exception hierarchies.
Defining your own error types can be of great value:
- You’ll make potential error cases stand out clearly → your functions and modules will become more maintainable.
- You can also use custom error types to provide additional debugging information.
→ All of this will improve your Python code and make it easier to under- stand, easier to debug, and more maintainable.
Example: Let’s say you wanted to validate an input string representing a person’s name in your application.
def validate(name):
if len(name) < 10:
raise ValueError
However, there’s a downside to using a “high-level” generic exception class like ValueError
. When a name fails to validate, it’ll look like this in the debug stack trace:
>>> validate('joe')
Traceback (most recent call last):
File "<input>", line 1, in <module>
validate('joe')
File "<input>", line 3, in validate
raise ValueError
ValueError
This stack trace isn’t really all that helpful. To be able to fix the problem, your teammate almost certainly has to look up the implementation of validate()
. This could be time consuming.
An improvement for this is to introduce a custom exception type to represent a failed name validation:
class NameToShortError(ValueError):
pass
def validate(name):
if len(name) < 10:
raise NameToShortError
The custom NameTooShortError
exception is “self-documenting”, which results in a much nicer stack track when the validation fails:
>>> validate('jane')
Traceback (most recent call last):
File "<input>", line 1, in <module>
validate('jane')
File "<input>", line 3, in validate
raise NameTooShortError(name)
NameTooShortError: jane
Custom exception classes make it much easier to understand what’s going on when things go wrong (and eventually they always do). By spending just 30 seconds on defining a simple exception class, this code snippet became much more communicative already.
Good Practice
It’s good practice to create a custom exception base class for the module and then derive all of your other exceptions from it.
Declare a base class that all of our concrete errors will inherit from. E.g.
class BaseValidationError(ValueError): pass
All of our “real” error classes can be derived from the base error class. This gives a nice and clean exception hierarchy with little extra effort.
E.g.
class NameTooShortError(BaseValidationError): pass class NameTooLongError(BaseValidationError): pass class NameTooCuteError(BaseValidationError): pass
Of course you can take this idea further and logically group your exceptions into fine grained sub-hierarchies. But be careful—it’s easy to introduce unnecessary complexity by going overboard with this.
In conclusion, defining custom exception classes makes it easier for your users to adopt an it’s easier to ask for forgiveness than permission (EAFP) coding style that’s considered more Pythonic.