Have you ever thought about creating or customizing the error messages to meet the requirements of your Python application? Yes, you can do so with the assistance of custom or user-defined Python exceptions.
This is the last article of our Python Exception handling series, in which we have deeply discussed Python Exceptions and different approaches for exception handling. Now, let’s step up and check out the method of customizing the exceptions and the relevant concepts.
What are Python Custom/User-defined Exceptions
Python enables you to create your own exceptions. These types of exceptions are known as User-defined or Custom exceptions. Moreover, you can customize these exceptions as per your needs.
Custom or user-defined exceptions allow you to handle those scenarios which are beyond the built-in exceptions. More specifically, by using custom or user-defined exceptions, you can improve the clarity of the code and handle the error effectively.
How to Create Custom/User-defined Exceptions
In Python, creating Custom or User-defined Exceptions permit you to design error-handling mechanisms with respect to your application requirements. Additionally, by defining custom exception classes, you can handle particular scenarios in an efficient manner.
Define and Implement Custom Exception Classes
In order to define a custom or user-defined class, it is required to create a new class that inherits the built-in “Exception
” or any of its subclasses.
This class behaves as the blueprint for the defined custom exception. It also allows you to add methods or attributes for making it more informative.
Here, we have created a custom class named “InsufficientFundsError
” having an initialization method “__init__()
“. This method provides the current balance and the required amount for the error message.
Next comes the “withdraw()
” function that raises this custom exception when there exist insufficient funds.
class InsufficientFundsError(Exception): def __init__(self, balance, amount): self.balance = balance self.amount = amount super().__init__(f"Insufficient funds: Available balance {balance}, required {amount}") def withdraw(balance, amount): if amount > balance: raise InsufficientFundsError(balance, amount) return balance - amount try: account_balance = 1000 withdrawal_amount = 1500 new_balance = withdraw(account_balance, withdrawal_amount) except InsufficientFundsError as e: print(f"Error: {e}") else: print(f"Withdrawal successful. New balance: {new_balance}")
Inherit From the Base “Exception” Class
Inheriting from the base “Exception
” class enables you to create a hierarchy of custom exceptions that can share common behaviors of a standard exception.
According to the given program, a hierarchy of custom experiences has been created. This is done with “EmptyInputError
” and “InvalidFormatError
” inheriting from the base “InputValidationError
“.
More specifically, the “validate_email()
” function raises the specified exceptions according to the rules of input validation.
class InputValidationError(Exception): pass class EmptyInputError(InputValidationError): def __init__(self, field): self.field = field super().__init__(f"Empty input error: {field} cannot be empty") class InvalidFormatError(InputValidationError): def __init__(self, field, format_type): self.field = field self.format_type = format_type super().__init__(f"Invalid format error: {field} should be in {format_type} format") def validate_email(email): if not email: raise EmptyInputError("Email") if "@" not in email: raise InvalidFormatError("Email", "email address") try: user_email = input("Enter your email: ") validate_email(user_email) except InputValidationError as e: print(f"Error: {e}") else: print("Email validation successful.")
In the first case, we will input an email address in the correct format. For this scenario, the output signifies that email validation has been done successfully.
Now, let’s enter an invalid email address. It can be observed that the “InvalidFormatError
” exception has been raised successfully.
How to Raise User-defined Exceptions in Python
In Python, the “raise
” statement can be utilized for triggering the exceptions when particular conditions are met. More specifically, raising custom or user-defined exceptions permits you to create certain error conditions for your Python applications.
For instance, in the following example, we have defined a custom exception class named “CustomError
” This class has a “check_value()
” function that raises a “CustomError
” if the input “x
” value is negative.
The “try-except” block will catch the exception and display the custom error message with the print() function.
class CustomError(Exception): def __init__(self, message): self.message = message def check_value(x): if x < 0: raise CustomError("Negative value not allowed") try: value = -5 check_value(value) except CustomError as e: print(f"CustomError: {e.message}")
How to Catch User-defined Exceptions in Python
As discussed earlier, custom or user-defined exceptions can be caught by using a “try-except
” block. It can particularly handle error scenarios defined by the custom exception classes.
Here, we have added a “process_data()
” function that raises a “CustomError
” exception if an empty list has been passed as an argument.
This exception will be caught in the “try-except
” block and the respective message will be shown on the terminal.
class CustomError(Exception): def __init__(self, message): self.message = message def process_data(data): try: if not data: raise CustomError("Empty data provided") # Process the data here except CustomError as e: print(f"CustomError: {e.message}") data = [] process_data(data)
Customize Exception Behaviour in Python
This example code comprises a custom exception class named “CustomError
” which accepts a custom error message and a code during initializing.
So, when the exception is raised, the added message and the relevant information will provide specific details about the error on the console.
class CustomError(Exception): def __init__(self, message, code): self.message = message self.code = code super().__init__(message) try: raise CustomError("Custom exception message", 123) except CustomError as e: print(f"Error: {e.message}, Code: {e.code}")
Add Context to User-defined Exceptions in Python
Here, a custom exception class named “DatabaseError
” has been created. This class has an additional argument that stores the database query that encountered the error.
More specifically, when the exception will be raised due to a missing table, the error message along with the corresponding query will be shown.
This ultimately provides more context related to the nature of the triggered database error.
class DatabaseError(Exception): def __init__(self, message, query): self.message = message self.query = query super().__init__(f"Database error: {message}\nQuery: {query}") try: query = "SELECT * FROM non_existent_table" raise DatabaseError("Table not found", query) except DatabaseError as e: print(f"Error: {e}")
That brought us to the end of our Python exception-handling series.
Conclusion
The mechanisms related to Python exception handling offer a robust way to manage and respond to several runtime errors. Specifically, the built-in exceptions cover a wide range of scenarios.
On the other hand, custom or user-defined exceptions enable you to customize error handling as per the requirements of your application.
By understanding how to raise and catch exceptions, you can improve the reliability and user-friendliness of your Python programs.
Want to explore and learn more related to Python, do check out our dedicated Python Tutorial Series!