Define and use custom exceptions
I have been developing software with Python for quite some time with little to no use of custom exceptions. However I’m trying hard nowadays to use and possibly abuse them. Let’s talk about why I changed my mind about them.
TL;DR: custom exceptions allow developers to cherry pick errors.
Custom exceptions are easy to create and use
With Python, custom exceptions are something really easy to create and use.
It is as simple as declaring a class that herits from Exception:
Perfect, you now have a new exception type. You can raise it in your code whenever appropriate.
Why use custom exceptions ?
The answer isn’t obvious. The standard library already comes with a lot of exceptions and it is very tempting and removes a lots of doubts and fears when using those predefined.
Let’s get an example about when default exceptions don’t match well.
Back in Python 2 days, a lot of
os functions would raise an
OSError exceptions may be a lot of different things. They range from permissions errors, file does not exist to disk or network failures, too many open files or lot of other things. The only way to figure out — say if the file is simply missing from a hard drive failure — is to catch the exception, check the
errno code and re-raise the exception:
Same code in Python 3:
As you can see, it’s both simplier and easier to read.
There are even more complex examples or even sometime cases where you just can’t know for sure what’s happening. Raising — say — an
AttributeError is a terrible thing to do. Let’s take
my_function().something. How can one figure out whether the function produced that exception or if accessing something produced it ? What if the function raises the same exception as the underlying libraries ? Too often the root cause is different and will require a different handling. How can that be possible if the exceptions look the same ?
Custom exceptions are easy to introduce. In the example,
IsADirectoryError inherits from
OSError. That means that upgrading the
fopen code to use the new exception won’t break our legacy code. Catching
OSError will still work !
This means that you can migrate legacy code bases in a totally backward compatible way.