Python Custom Exceptions
Custom Exception
Python had different built-in exceptions that are raised when something in a program went wrong.
In some cases, we may need to create our own custom exceptions that serve a specific purpose.
Creating Custom Exceptions
In Python, we can define custom exceptions by creating a new class. This exception class has to be derived directly or indirectly from the built-in Exception
class.
Most of the built-in exceptions in Python are derived from the Exception
class.
>>> class CustomError(Exception):
. . . pass
. . .
>>> raise CustomError
Traceback (most recent call last)
...
CustomError:
>>> raise CustomError("An error occurred")
Traceback (most recent call last)
...
CustomError: An error occurred
Here above, we have created a user-defined exception named CustomError
that inherits from the Exception
class. This new exception, like others exceptions, can be raised with the help of the raise
statement that accepts an optional error message.
When our python program starts to grow up, it is a good practice to put all the user-defined exceptions in a separate file. Various standard modules do this. They generally define their exceptions separately as errors.py
or exceptions.py
.
A user-defined exception can implement everything a standard class can do. However, we generally make the user-defined exceptions concise and straightforward. Most implementations declare a custom base class and derive other exception classes from it. This approach is explained in the following example.
Example: User-Defined Exception in Python
In this example, we will see how user-defined exceptions can be used in a program to raise and catch errors.
In the following program, we will ask the user to keep entering a number until they guess the stored number correctly. To help the user figure out the stored number, we will provide a hint of whether their guess is greater than or less than the stored number.
# define Python user-defined exceptions
class BaseError(Exception):
"""Base class for other exceptions"""
pass
class ValueTooSmallError(BaseError):
"""Raised when the input value is too small"""
pass
class ValueTooLargeError(BaseError):
"""Raised when the input value is too large"""
pass
# we need to guess this number
num = 9
while True:
try:
in_num = int(input("Enter a number:"))
if in_num > num:
raise ValueTooLargeError
elif in_num < num:
raise ValueTooSmallError
break
except ValueTooLargeError:
print("This value is too large, try again!")
print()
except ValueTooSmallError:
print("This value is too small, try again!")
print()
print("Congratulation: You guessed it correctly.")
Here is an example run of the above program.
Enter a number:20
This value is too large, try again!
Enter a number:12
This value is too large, try again!
Enter a number:3
This value is too small, try again!
Enter a number:8
This value is too small, try again!
Enter a number:9
Congratulation: You guessed it correctly.
In the above code, we have defined a base class called BaseError
.
The two exceptions ValueTooLargeError
and ValueTooSmallError
that are raised by the program are derived from the BaseError
class. This is the common way to define user-defined exceptions, but we are not limited to this way.
Customizing Exception Classes
We can also customize a user-defined exception class to accept other arguments.
Let us see the following example:
class MarkNotInRangeError(Exception):
"""Exception raised for errors in the input mark
Attributes
mark -- input mark which caused the error
message -- explanation of the error
"""
def __init__(self, mark, message="Mark is not in (0, 100) range"):
self.mark = mark
self.message = message
super().__init__(self.message)
mark = int(input("Enter mark of student: "))
if not 0 <= mark <= 100:
raise MarkNotInRangeError(mark)
Output
Enter mark of student: 150
Traceback (most recent call last)
---> 15 raise MarkNotInRangeError(mark)
MarkNotInRangeError: Mark is not in (0, 100) range
In the above code, we have overridden the constructor of the Exception
class to accept our own custom arguments mark
and message
. Then, the constructor of the parent Exception
class is called manually with the self.message
argument using super()
.
The self.mark
attribute is defined to be used later.
When the MarkNotInRangeError
is raised, implicitly, the inherited __str__
method of the Exception
class is then used to display the corresponding message.
We can also customize the __str__
method itself by overriding it.
class MarkNotInRangeError(Exception):
"""Exception raised for errors in the input mark
Attributes
mark -- input mark which caused the error
message -- explanation of the error
"""
def __init__(self, mark, message="Mark is not in (0, 100) range"):
self.mark = mark
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.mark} -> {self.message}'
mark = int(input("Enter mark of student: "))
if not 0 <= mark <= 100:
raise MarkNotInRangeError(mark)
Output
Enter mark of student: 123
Traceback (most recent call last)
---> 18 raise MarkNotInRangeError(mark)
MarkNotInRangeError: 123 -> Mark is not in (0, 100) range
To learn more about how to handle exceptions in Python, you can visit Python Exception Handling.