9.2 Custom Exceptions
Built-in exceptions handle many general errors, but real projects often have business-rule failures. “Out of stock” is not a Python syntax error or a type error; it is a violated business rule.
Defining an Exception Class
Custom exceptions usually inherit from Exception.
class OutOfStockError(Exception):
passIn many cases, the custom exception class can start with only pass. The message can be passed when raising it:
raise OutOfStockError("Notebook is out of stock.")The exception name should clearly express the error. OutOfStockError is more specific and easier for callers to recognize than a generic Exception.
Stock Example
class OutOfStockError(Exception):
pass
class Product:
def __init__(self, name, stock):
self.name = name
self.stock = stock
def purchase(self, quantity):
if quantity <= 0:
raise ValueError("Quantity must be greater than 0.")
if quantity > self.stock:
raise OutOfStockError("%s is out of stock." % self.name)
self.stock -= quantity
product = Product("Notebook", 5)
try:
product.purchase(3)
print("Purchase succeeded. Remaining stock: %d" % product.stock)
product.purchase(4)
except OutOfStockError as error:
print("Purchase failed: %s" % error)Output:
Purchase succeeded. Remaining stock: 2
Purchase failed: Notebook is out of stock.In this example, ValueError means the argument itself is unreasonable, while OutOfStockError means a business rule blocks the purchase. Different exceptions express different problems, so caller code can respond more accurately.
Why Custom Exceptions Matter
The value of custom exceptions is not merely that they can throw errors. They give errors semantics.
When caller code catches OutOfStockError, it knows the problem is stock-related and can show business actions such as restocking or choosing another product. When it catches ValueError, it is more likely to ask the user to change the quantity.