Learn the best practices for declaring custom exceptions in modern Python, including inheritance, exception details, and raising exceptions effectively.
In this guide, we'll explore how to create and utilize custom exceptions in Python to enhance your error handling. We'll cover the process of defining custom exception classes, raising them when specific conditions occur in your code, and gracefully handling these exceptions to prevent abrupt program termination. Additionally, we'll delve into scenarios where creating custom exceptions is particularly beneficial and outline best practices to ensure clarity and maintainability in your exception handling code.
Inherit from Exception
: Begin by creating a new class for your custom exception. This class should inherit from the built-in Exception
class. This establishes it as an exception type within Python's system.
class MyCustomError(Exception):
pass
Optional: Add an __init__
method: If you want your custom exception to carry additional information beyond a simple message, define an __init__
method. This method allows you to initialize the exception instance with specific attributes.
class MyCustomError(Exception):
def __init__(self, message, error_code):
super().__init__(message)
self.error_code = error_code
Raise the exception: When an exceptional situation arises in your code that warrants signaling an error, use the raise
keyword along with your custom exception class. You can provide an informative message and any relevant data.
def my_function(value):
if value < 0:
raise MyCustomError("Value cannot be negative", 400)
Handle the exception: In parts of your code where you anticipate the possibility of this custom exception being raised, use a try...except
block to gracefully catch and handle it.
try:
my_function(-5)
except MyCustomError as e:
print(f"An error occurred: {e.args[0]} (Code: {e.error_code})")
When to Create Custom Exceptions:
Best Practices:
This Python code defines a custom exception class called InvalidInputError to handle cases where an invalid input is provided to a function. It then defines a function calculate_square_root that calculates the square root of a number, raising the InvalidInputError if the input is negative. Finally, the code demonstrates how to handle the custom exception, printing an error message and the invalid input value if the exception is raised.
# 1. Define the custom exception class
class InvalidInputError(Exception):
"""Custom exception for invalid input values."""
def __init__(self, message, input_value):
super().__init__(message)
self.input_value = input_value
# 2. Function that might raise the custom exception
def calculate_square_root(number):
"""Calculates the square root of a number.
Args:
number: The number to calculate the square root of.
Returns:
The square root of the number.
Raises:
InvalidInputError: If the input number is negative.
"""
if number < 0:
raise InvalidInputError("Cannot calculate square root of a negative number", number)
return number**0.5
# 3. Handling the custom exception
if __name__ == "__main__":
try:
result = calculate_square_root(-9)
print(f"The square root is: {result}")
except InvalidInputError as e:
print(f"Error: {e}")
print(f"Invalid input value: {e.input_value}")
Explanation:
InvalidInputError
Class:
Exception
class.__init__
method to store the error message and the invalid input value.calculate_square_root
Function:
number
as input.InvalidInputError
if the number
is negative.Exception Handling:
try...except
block attempts to call calculate_square_root
.InvalidInputError
is raised, the except
block catches it:
e
).e.input_value
.Key Points:
InvalidInputError
clearly indicates the type of error.input_value
attribute stores the problematic input.except
block handles InvalidInputError
specifically, allowing other exceptions to be raised if needed.General:
ValueError
, TypeError
, IOError
).Inheritance:
Exception
is fine.__init__
Method:
super().__init__(message)
: Always call the parent class's __init__
to ensure the exception message is properly initialized.Raising and Handling:
except
Blocks: Catch custom exceptions with except MyCustomError as e:
to handle them differently from other errors.raise ... from e
to preserve the original error's traceback for debugging.Example Use Cases:
This guide explains how to define and utilize custom exceptions in Python to improve error handling and code clarity.
1. Defining Custom Exceptions:
Exception
class.__init__
method to store additional information like error codes or relevant data.2. Raising Custom Exceptions:
raise
keyword with your custom exception class when a specific error condition occurs.3. Handling Custom Exceptions:
try...except
blocks to gracefully catch and handle your custom exceptions.When to Use Custom Exceptions:
Best Practices:
By understanding how to create, raise, and handle custom exceptions, you can write more robust, maintainable, and informative Python code. Remember to use clear naming conventions, provide detailed documentation, and consider the hierarchy and relationships between your custom exceptions. This will not only make your code easier to debug but also improve its overall structure and readability.