You've come to the right place if you want to learn how to create and use custom exceptions in Python. This topic is essential because it empowers you to handle errors more effectively, write cleaner code, and improve your applications' overall robustness. By the end of this guide, you'll know everything you need about raising custom exceptions.
Custom exceptions allow you to create error classes that are specific to your application or problem domain. This lets you provide meaningful, context-aware error messages when things go wrong, improving your code's readability and maintainability. To define a custom exception, we use the Exception
class as a base and inherit from it, providing an appropriate name and message.
Here's a simple example:
class CustomException(Exception):
def __init__(self, message="An error occurred"):
super().__init__(message)
In this example, we created a custom exception named CustomException
. When an instance of this class is raised, it will propagate the given error message.
Let's consider a simple bank account application where accounts have a balance limit. We can create a custom exception called BalanceLimitExceeded
:
class BalanceLimitExceeded(Exception):
def __init__(self, current_balance, limit):
message = f"Balance cannot exceed {limit}, current balance is {current_balance}"
super().__init__(message)
def deposit(account, amount):
if account.balance + amount > account.limit:
raise BalanceLimitExceeded(account.balance + amount, account.limit)
account.balance += amount
In this example, we defined a deposit()
function that raises a BalanceLimitExceeded
exception if the deposit amount exceeds the account's limit. The constructor for BalanceLimitExceeded
includes the current balance and the limit as arguments, which are used to provide a meaningful error message.
What causes it: Failing to define the custom exception class before attempting to use it in your code.
# Bad code example that triggers the error
try:
deposit(account, 10000)
except BalanceLimitExceeded:
print("Balance limit exceeded")
Error message:
Traceback (most recent call last):
File "example.py", line 25, in <module>
deposit(account, 10000)
File "example.py", line 22, in deposit
raise BalanceLimitExceeded(account.balance + amount, account.limit)
NameError: name 'BalanceLimitExceeded' is not defined
Solution: Make sure to define the custom exception class before using it.
# Corrected code
class BalanceLimitExceeded(Exception):
def __init__(self, current_balance, limit):
message = f"Balance cannot exceed {limit}, current balance is {current_balance}"
super().__init__(message)
try:
deposit(account, 10000)
except BalanceLimitExceeded:
print("Balance limit exceeded")
Why it happens: The interpreter doesn't know about the custom exception unless you define it.
How to prevent it: Define your custom exceptions before using them.
What causes it: Passing incorrect types of arguments to the constructor of a custom exception.
# Bad code example that triggers the error
class BalanceLimitExceeded(Exception):
def __init__(self, message="An error occurred"):
super().__init__(message)
try:
deposit("account", 10000)
except BalanceLimitExceeded:
print("Balance limit exceeded")
Error message:
Traceback (most recent call last):
File "example.py", line 25, in <module>
deposit("account", 10000)
TypeError: __init__() takes exactly 3 arguments (2 given)
Solution: Make sure to pass the correct number and types of arguments to the constructor.
# Corrected code
class BalanceLimitExceeded(Exception):
def __init__(self, current_balance, limit):
message = f"Balance cannot exceed {limit}, current balance is {current_balance}"
super().__init__(message)
try:
deposit(Account("account"), 10000)
except BalanceLimitExceeded:
print("Balance limit exceeded")
Why it happens: The custom exception constructor expects specific arguments, but the wrong types or number of arguments were passed.
How to prevent it: Ensure that you pass the correct number and types of arguments to the constructor.
What causes it: Accessing an attribute on an object that doesn't have it.
# Bad code example that triggers the error
class Account:
def __init__(self, balance):
self.balance = balance
def deposit(account, amount):
if account + amount > account.limit:
raise BalanceLimitExceeded(account.balance + amount, account.limit)
account.balance += amount
Error message:
Traceback (most recent call last):
File "example.py", line 28, in deposit
if account + amount > account.limit:
AttributeError: 'Account' object has no attribute 'limit'
Solution: Make sure to define the necessary attributes on your objects.
# Corrected code
class Account:
def __init__(self, balance, limit):
self.balance = balance
self.limit = limit
def deposit(account, amount):
if account.balance + amount > account.limit:
raise BalanceLimitExceeded(account.balance + amount, account.limit)
account.balance += amount
Why it happens: The Account
object doesn't have a limit
attribute, so accessing it causes an AttributeError.
How to prevent it: Ensure that the necessary attributes are defined on your objects before attempting to access them.
Exception
and providing an appropriate name and message.Next steps for learning:
- Learn how to handle exceptions more effectively using try/except blocks.
- Explore advanced exception handling techniques such as context managers and decorators.
- Familiarize yourself with Python's built-in exceptions and error classes.