Python Custom Exceptions
A custom exception is an error class that names one kind of failure in an app.
Make your own error
A custom exception is a class. It inherits from Exception, like every normal error.
class EmptyNameError(Exception):
pass
try:
raise EmptyNameError("Name is empty")
except EmptyNameError as err:
print(type(err).__name__)
print(err)Carry data as attributes
Your error can store extra values. Code that catches it can then read those values.
class ShortfallError(Exception):
def __init__(self, needed, have):
super().__init__(f"Need {needed}, have {have}")
self.needed = needed
self.have = have
try:
raise ShortfallError(50, 20)
except ShortfallError as err:
print(err)
print(err.needed)
print(err.have)A small family of errors
One base error can have child errors. Catching the base catches every child.
class BankError(Exception):
pass
class LowFundsError(BankError):
pass
class FrozenError(BankError):
pass
try:
raise FrozenError("Wallet is frozen")
except BankError as err:
print(type(err).__name__)
print(err)Check the parent class
Every custom error should pass this check. It should be an Exception under the hood.
class BankError(Exception):
pass
print(issubclass(BankError, Exception))Example
class BankError(Exception):
pass
class LowFundsError(BankError):
def __init__(self, needed, have):
super().__init__(f"Need {needed}, have {have}")
self.needed = needed
self.have = have
class FrozenError(BankError):
pass
class Wallet:
def __init__(self, balance, frozen=False):
self._balance = balance
self._frozen = frozen
def spend(self, amount):
if self._frozen:
raise FrozenError("Wallet is frozen")
if amount > self._balance:
raise LowFundsError(amount, self._balance)
self._balance -= amount
print(f"Spent {amount}. Left: {self._balance}")
wallet = Wallet(30)
wallet.spend(10)
try:
wallet.spend(50)
except LowFundsError as err:
print(type(err).__name__)
print(err)
print(f"Short by {err.needed - err.have}")
frozen = Wallet(30, frozen=True)
try:
frozen.spend(5)
except BankError as err:
print(type(err).__name__)
print(err)Key points
- Custom exception: an error class you define to name one kind of failure in your app
- Use class MyError(Exception) to define a custom exception
- Use attributes on the exception object to carry data, such as amounts or names
- Use one base error for a family, so one except can catch the whole family
- Use the suffix Error at the end of custom exception names
In this example, BankError is the base of a small family. LowFundsError carries the needed and held amounts as attributes. FrozenError needs no extra data, so its body is just pass. This Wallet is the beginner course's wallet, rebuilt. Its spend now raises an error instead of printing a refusal. The Wallet class raises FrozenError when the wallet is frozen. It raises LowFundsError when a spend asks for too much. The first spend of 10 succeeds and prints the new balance. The second spend asks for 50 and fails. The except block reads err.needed and err.have to print the shortfall. The last try catches FrozenError through the shared BankError base.
Note
Never subclass BaseException directly.
It also covers system exits like KeyboardInterrupt, so subclass Exception instead.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Python Playground
Exercise
Why do we subclass Exception and not BaseException?