Python: How to Create a Custom Exception

In this article, let us learn how to create a custom exception in Python with a help of a few examples.

For those of you in a hurry here is the short version of the answer.

Custom Exception Creation: The Recipe

To create a custom exception, you simply have to define and create a class that inherits the Exception class, just like this:

class CustomError(Exception):
	#custom error code

Here is an example.

Suppose for whatever reason you’re making a program that only accepts even numbers from users. You can raise an exception if the user has entered an odd number like this:

class OddNumberException(Exception):
    pass

number = int(input("Please enter a even number: "))
if number % 2 == 1:
    raise OddNumberException("An odd number was entered")
else:
    print("Thank you for your input")

OUTPUT 1:

Please enter a even number: 1
Traceback (most recent call last):
  File "<string>", line 6, in <module>
OddNumberException: An odd number was entered

OUTPUT 2:

Please enter a even number: 8
Thank you for your input

Making a custom exception is really that simple!

The difficult/interesting part is making the decision of

  • when to go for a custom exception instead of using built in exceptions and
  • which built-in exception to inherit from when making custom exceptions.

The article linked below address the above 2 questions in detail.

Python: When To Use Custom Exceptions? Explained!

Python: Hierarchy of Exceptions

And that it for “The Short version of the Answer”!

Don’t worry if the above answer does not make sense to you as that was targeted at more experienced programmers who just wanted to refresh their memories. The rest of this article is dedicated to those of you in the first steps of your journey to becoming a Python Craftsman.

By the time you reach the end of this article, I suggest you come back and read this summary once more, I assure you it will make much more sense then!

Creating a custom exception, the detailed explanation

Lets start with a quick refresher of what custom exceptions are.

What are Custom Exceptions?

In simple words, a “custom exception” a.k.a a “user-defined exception” is an exception that you yourself have defined and designed (as opposed to built-in exceptions)

How do I make one?

To create a custom exception, you have to define a class that inherits from the built-in Exception class (or you can also inherit from one of the Exception class’s subclass such as ArithmeticError class):

class my_custom(Exception):
    "This is my custom Exception class"
    pass
#An example program showing a custom exception
class CustomException(Exception):
    """This is my custom exception!"""

try:
    raise CustomException('Custom exception raised!')
except CustomException as e:
    print(e)

OUTPUT:

Custom exception raised!

Explanation:
In the above example, we’ve created a custom exception by creating a class that inherits from the Exception class.

Now we need to raise this exception to see if it’s working. We use a try-block so that we’re able to handle it once we’ve successfully raised it.

So use the try block to raise it:

try:
    raise CustomException('Custom exception raised!')

And then catch it using the except block so that we can handle it:

except CustomException as e:
    print(e)

Here, we’ve specified that an exception of the name CustomException to be caught. The way this is processed is, all the exceptions of the class CustomException and its subclasses (if any) will be caught. 
This means if you specified our CustomExceptionsuperclass: the Exception class, this code will still work in the same manner:

except Exception as e:
    print(e)

To know more about catching exceptions, refer to this article:

Python: Catch Exception and Print

How to choose which built in exception to inherit from?

Choosing the best inbuilt exception to inherit from is also something you have to consider when building a custom exception, as choosing the perfect class will

  • Communicate the idea behind the class for users of your code
  • Easier to edit it, as it will already have most of the features you need.

To choose the perfect class to inherit from, one must first understand the hierarchy using which Built-in Exceptions are built. That is a big topic and far beyond the focus of this article. But fear not, we got you covered! You can learn about the Hierarchy of built-in exceptions in our other article linked below.

Python: Hierarchy of Exceptions

I also invite you to checkout our video on top 7 built in exception to get a quick overview of some of the most common exceptions in python.

Time for an example!

Now that you know how to create a custom exception, let’s move on to implementing it and creating an actual example.

Note: Before I show the code, why don’t you try to write it by yourself? Here’s what must be done:

  1. Create a custom exception ZeroError. Keeping one statement inside it is enough (for example you can keep the pass statement itself)
  1. Define a function that accepts two parameters, num1, and num2. If num2 is equal to 0, raise ZeroError with a custom message of your own. Else, return the division of num1 by num2.
  1. Now use a try-block to call the function;
  2. In the try block, call the function with parameters of your own choice and print the results. 

In the except block, catch ZeroError and store it as an object. Print this object.

Congratulations to those of you who got it, and for those who didn’t, don’t worry here’s how you do it:

class ZeroError(Exception):
    """This exception is raised when you divide something by 0"""
    pass

def divide(num1, num2):
    if num2 == 0:
        raise ZeroError("You cannot divide a number by zero")
    else:
        return num1/num2

try:
    result = divide(4, 0)
    print(result)
except ZeroError as e:
    print("Oops! This resulted in an error:", e)

OUTPUT:

Oops! This resulted in an error: You cannot divide a number by zero

More customization!

We can also customize our exception further by editing our class’s attributes. If you recall, we create an exception by defining a class and making it inherit the Exception class. This means our exception now has all the attributes of the Exception class.

Now in certain scenarios, you might want to change these attributes to suit your code better and to add more functionality. To do that you need to know whats already implemented in a given exception class.

The “Exception” class is the one from which most built-in exception classes are built from, you can explore what is inside that one by reading the article below.

“Exception” Class in Python: A Walk-through!

Next, lets look at how we can use the __str__() method to customize our Custom-exception class!

Customizing the __str__() method to add more clues in the error message

The __str__ method is called when you use the print() method on an object of a any class in python. It returns a string, which is usually the name of the class.

The __str__ function exists in all exception classes hence it is included in the Exception class too. When we create a custom exception, we inherit this __str__ function.

If you wish to, you can have your own __str__ function in your custom exception (which is nothing but the child class) by overriding the function in the Exception class (that’s the parent class).

Customization Example#1

For example, look at the two pieces of code below:

In this code we override the parent class’s __str__() method:

class IncorrectScoreRangeError(Exception):
    def __init__(self, score):
        self.score = score

    def __str__(self):
        return f"IncorrectScoreRangeError: {self.score} is not in the valid (0, 100) range"

try:
    score = int(input("Enter your obtained score: "))
    if not 0 < score < 100:
        raise IncorrectScoreRangeError(score)
except IncorrectScoreRangeError as e:
    print(e)

OUTPUT

Enter your obtained score: 101
IncorrectScoreRangeError: 101 is not in the valid (0, 100) range

And this code didn’t use the __str__() method:

class IncorrectScoreRangeError(Exception):
    pass
try:
    score = int(input("Enter your obtained score: "))
    if not 0 < score < 100:
        raise IncorrectScoreRangeError("The entered score is not in the valid (0, 100) range")
except IncorrectScoreRangeError as e:
    print(e)

OUTPUT:

Enter your obtained score: -5
The entered score is not in the valid (0, 100) range

Notice how the __str__() method helps in further customizing the output by printing the score by printing the actual value that led to the error!

Lets have a look at another example just to gain more understanding!

Customization Example#2

Lets say we need to develop a program that calculates the grade based on the user’s score. To do that, we need to

  • get the input score from the user
  • calculate the grade from the score

Now if the entered score is not in the range (1 to 100) we’ll simply raise our error.

Let’s start by creating the function that calculates the grades

The Function
def grade_calculator(score):
    if score >= 90: return "A"
    if score >= 80: return "B"
    if score >= 70: return "C"
    if score >= 60: return "D"
    return "F"
    
print(grade_calculator(78))

The function grade_calculator takes in a parameter score and returns a grade based on it.

Next lets define our custom exception for “score is out of range” scenario

The Customized Exception Class
class ScoreError(ValueError):
    min_score = 0
    max_score = 100

    def __init__(self, score, *args):
        super().__init__(args)
        self.score = score

    def __str__(self):
        return f'ScoreError: Your entered score {self.score} is not in the valid range required: {self.min_score, self.max_score}'

Here we have:

  1. Defined a custom exception class that inherits from the ValueError class
  2. Added two attributes to the class, min_score and max_score.
  3. Created a function called __init__ that takes in a parameter called score and any number of position arguments *args.
    • Use the super() keyword to call the __init__ method of the base class (which is the Exception class in this case)
    • Create the __str__ function to override the base class’s __str__ function so that you can print out your own custom message exception

Here is a quick side note on the super() method in python if you are not familiar with the concept!

The super() method

This is nothing but a keyword used to access overridden parent class methods from the child class.

i.e let’s say there was a function called my_func in the parent class, if you defined a function named my_func in the child class, this child class’s function would be used whenever called. The child class’s function has overridden the parent class function. The super() keyword allows you to access the parent class’s function even if it is overridden!

Example:

#creating a parent class with its method
class ParentClass:
    def my_method(self):
        print("I am a method from the parent class")

#creating a child class with its method
class ChildClass(ParentClass):
    #by defining using the same class name again, we have overridden the 'ParentClass' method with this 'ChildClass' method
    def my_method(self):
        print("I am a method from the child class")
        #the super keyword calls the 'ParentClass' method again
        super().my_method()
        
#creating a ChildClass object
child_obj = ChildClass()
#calling the 'my_method'
child_obj.my_method()

OUTPUT:

I am a method from the child class
I am a method from the parent class

The script which uses the above method and custom exception class is given below.

User’s Code
score = int(input("Please enter your score: "))
try:
  grade = grade_calculator(score)
  print(f'{score} score= {grade} grade')
except ScoreError as ex:
  print(ex)

How it works:

  1. Take the input from the user and store it in a variable called score
  2. Try to convert the variable score to an integer, if the user entered a number, the code works and moves to the next statement, otherwise a ValueError is raised.
  3. In the else block,
    • We use another try block to call the grade_calculator function that we previously had defined by entering score as the parameter.
    • If the score happens to be out of range, ScoreError will be raised and handled in the except block
    • In the else block, the converted grade is converted and printed to the output screen
Putting it all together
def grade_calculator(score):
    if score < ScoreError.min_score or score> ScoreError.max_score:
        raise ScoreError(score)

    if score >= 90: return "A"
    if score >= 80: return "B"
    if score >= 70: return "C"
    if score >= 60: return "D"
    return "F"

class ScoreError(ValueError):
    min_score = 0
    max_score = 100

    def __init__(self, score, *args):
        super().__init__(args)
        self.score = score

    def __str__(self):
        return f'ScoreError: Your entered score {self.score} is not in the valid range required: {self.min_score, self.max_score}'



score = int(input("Please enter your score: "))
try:
  grade = grade_calculator(score)
  print(f'{score} score= {grade} grade')
except ScoreError as ex:
  print(ex)

When the score entered is in the expected range, no exception will be raised and we will get the following output.

Please enter your score: 65
65 score= D grade

If the user enters some absurd value, we will raise a ScoreError as shown below.

Please enter your score: 101
ScoreError: Your entered score 101 is not in the valid range required: (0, 100)

Again we got a similar result to the previous example, this time with even more information in the error message.

I hope with these 2 examples, things are more clear to you and you got some idea now on how to customize your own custom exception class!

And with that, I will end this article.

Congratulations for making it till the end of the article, not many have the perseverance to do so!

I hope you enjoyed reading this article and found it useful!

Feel free to share it with your friends and colleagues!

If your thirst for knowledge have not been quenched yet, here are some related articles that might spark your interest!

Related Articles

Python: When To Use Custom Exceptions? Explained!

“Exception” Class in Python: A Walk-through!

Python: Details contained in an Exception

Thanks to Namazi Jamal for his contributions in writing this article!

Photo of author
Editor
Balaji Gunasekaran
Balaji Gunasekaran is a Senior Software Engineer with a Master of Science degree in Mechatronics and a bachelor’s degree in Electrical and Electronics Engineering. He loves to write about tech and has written more than 300 articles. He has also published the book “Cracking the Embedded Software Engineering Interview”. You can follow him on LinkedIn