How to Handle Specific Errors in Python with User-Defined Exceptions

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}")
Define and Implement Custom Exception Classes
Define and Implement Custom Exception Classes

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.

Inherit From the Base "Exception" Class
Inherit From the Base “Exception” Class

Now, let’s enter an invalid email address. It can be observed that the “InvalidFormatError” exception has been raised successfully.

Inherit From the Base Exception Class InvalidFormatError
Inherit From the Base Exception Class InvalidFormatError

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}")
Raise User-defined Exceptions in Python
Raise User-defined Exceptions in Python

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)
Catch User-defined Exceptions in Python
Catch User-defined Exceptions in Python

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}")
Customize Exception Behaviour in Python
Customize Exception Behaviour in Python

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}")
Add Context to User-defined Exceptions in Python
Add Context to User-defined Exceptions in Python

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!

If you read this far, tweet to the author to show them you care. Tweet a thanks
As a professional content writer with 3 years of experience, I specialize in creating high-quality, SEO-optimized content that engages, attracts, and retains the audience.

Each tutorial at GeeksVeda is created by a team of experienced writers so that it meets our high-quality standards.

Join the GeeksVeda Weekly Newsletter (More Than 5,467 Programmers Have Subscribed)
Was this article helpful? Please add a comment to show your appreciation and support.

Got Something to Say? Join the Discussion...