In this article let us learn how to manually throw an exception in Python.
How to throw/raise an Exception in Python
An Exception can be manually thrown/raised using the raise statement in Python.
Let us start with a simple example.
raise Exception ('I just raised my 1st ever Exception in Python!')
Running that code will result in an output like below
Traceback (most recent call last): File "", line 1, in raise Exception ('I just raised my 1st ever Exception in Python!') Exception: I just raised my 1st ever Exception in Python!
As you can see, we have managed to throw an exception using the raise statement! This has caused the interpreter to crash the program just like a runtime error would!
Hence the statement we are looking for here is raise. But this is just the short version of the answer. Read on to find out how exactly to employ this raise statement in your code in a variety of situations.
The rest of the article explains
- The 3 major syntax/variants of the raise statement
- When and Where to use each of these syntax and
- The best practices to follow while using each of these syntax
So, let’s begin!
raise Syntax#1: Raise Exception with a Custom Error Message
The syntax shown in the example below (line 3) is the most common syntax you will see with the raise statement.
x = int(input('Please enter a even number: ')) if ( x % 2 != 0 ): raise ValueError('Input is an odd number, cannot continue Execution') else: # continue with whatever you want to do with the even number
In the example above, we are throwing a ValueError with the error message “The value is not as expected”.
For those of you who are very new to Python let us briefly see what ValueError is. According to the official python documentation
ValueError is raised when an operation or function receives an argument that has the right type but an inappropriate valuehttps://docs.python.org/3/library/exceptions.html#bltin-exceptions
which basically means the passed in argument is of the right type, but the value contained is meaningless to our program.
Running the code in Example-2 above will give you an output like this.
Please enter a even number: 9 Traceback (most recent call last): File "", line 3, in raise ValueError('Input is an odd number, cannot continue Execution') ValueError: Input is an odd number, cannot continue Execution
As you can see, the custom message we coded in is printed along with the exception name.
The syntax used in Example-2 is shown below. Replace the terms with the angle brackets ‘<>’ with whatever your program needs!
raise <ExceptionType> (<error message>)
Use this syntax when you wish to raise an Exception and pass a custom error message through that Exception. This custom message can either be sent to an output device to be seen by the user or to a log file, so that you, the programmer, can see these logs later and use the information there for debugging purposes.
In case you wish to catch the raised Exception from the calling code so that you can deal with that instead of ending your program, you can do so as shown in the example below
def checkForDivisibilityBy2(): x = int(input('Please enter a even number: ')) if ( x % 2 != 0 ): raise ValueError('Input is an odd number, cannot continue Execution') else: print('The entered number is divisible by 2') try: checkForDivisibilityBy2() except ValueError as err: print (str(err))
The output as you might have expected will look like this.
Please enter a even number: 9 Input is an odd number, cannot continue Execution
The syntax used in the above example is shown below. Replace the terms with the angle brackets ‘<>’ with whatever your program needs!
except <exception_type> as <exception_instance_name>: print ( str (<exception_instance_name>) )
Best Practices for Syntax#1
If you ever need to use this syntax in your Python code, remember these 2 points
- Be sure to word-smith a very specific error message, so that the ‘future-you’ or anyone else reading these error messages will understand what went wrong and
- Use an appropriate Exception type to raise.
See how ValueError suits this particular program. It is considered best practice to pick an appropriate Exception to raise, else you will end up hiding bugs leading to unreliable programs. We will see an example of such a situation after Syntax#2.
raise Syntax#2: Raise Exception without any Custom messages
Sometime, you may not need to log or print out messages to the user. In those situations you can use the syntax shown in the example below
The output on the interpreter will look like this
Traceback (most recent call last): File "", line 1, in raise ValueError ValueError
As you can see, the output has just the Exception class name and no error message.
The syntax used in the above example is shown below. As with previous syntax snippets, replace the terms with the angle brackets ‘<>’ with whatever your program needs!
What happens behind the scenes when we use this syntax?
The raise statement will expect the first object passed in to be an Exception object. If we pass a Class name as the argument to raise, the python interpreter will convert the code behind the scenes to be
which is a call to the constructor of the ValueError class with no arguments.
Similarly, in Syntax#1, what we wrote was raise followed by a call to the constructor with a string argument which is an attribute meant to be used as the error message. This constructor then returns a Exception object, which is what the raise statement needs!
If you wish to learn more about how this string is used in the error message, read my other article on printing exceptions below
The class which is passed with the raise statement must be a subclass of the BaseException class, which as the name implies is the base class for all the built-in Exception classes in Python.
You can find all the built-in exception classes that python provides in the python documentation here.
If you scroll down till the bottom of that page you can find the Exception Hierarchy tree as shown in the image below.
So just for fun, to see what happens, let us pass a list object to the raise statement!
list1 = [1,2,3,4] raise list1
If you run this code, the interpreter will raise a TypeError exception as the interpreter was expecting an object of “Exception type” and we passed in a “list type” object.
Traceback (most recent call last): File "", line 1, in raise list1 TypeError: exceptions must derive from BaseException
Now that we have understood how to use Syntax#2, let us next see when to use this syntax!
When to use Syntax#2 raise statement
Best time to use Syntax#2 is when you can recover from an Exception through code-substitution or default-value substitution. If you haven’t already, I suggest reading my other article which covers the basics of exception handling in Python.
In the article given in the link above, the sub-section “Strategy#2″ in the section “3 ways to handle Exceptions” explains how to recover from exceptions.
Syntax#2 best goes with such problems where it is possible to recover from exceptions and continue with the program execution.
Best Practices for Syntax#2 raise statement
As with Syntax#1 try using an appropriate type of Exception here, also make sure the exception you raise is very specific else you may end-up hiding bugs leading to a unreliable program.
Let us see a simple example of such a situation.
raise: How to avoid Hiding Bugs
Consider the snippet below.
def divide(numerator, denominator): return int(numerator)/int(denominator)
This function call can produce 2 types of exceptions.
The output below shows the 1st of the 2 types
>> divide(10, 0) Traceback (most recent call last): File "", line 1, in divide(10, 0) File "", line 2, in divide return numerator/denominator ZeroDivisionError: division by zero
Here we passed in the second argument as 0, and division by zero is not allowed in Math, and this resulted in ZeroDivisionError
The output below shows the 2nd type of exception that the code in Example#6 can produce
>> divide('pizza', 6) Traceback (most recent call last): File "", line 1, in divide('pizza', 6) File "", line 2, in divide return numerator/denominator TypeError: unsupported operand type(s) for /: 'str' and 'int'
Here we tried to divide a pizza into 6 pieces using our Math function and this resulted in TypeError!
Say for example, when we wrote the code we forgot about ValueError and we wrote code only to handle division by zeros as shown below.
def divide(numerator, denominator): if (denominator == 0): raise Exception else: return int(numerator)/int(denominator) try: x = input('Please enter the Numerator: ') y = input('Please enter the Denominator: ') print(x, ' / ', y, ' = ', str(divide(x,y))) except Exception: print("You have entered zero as denominator")
As you can see instead of using ZeroDivisionError type to raise the exception we used Exception type, which is higher in the hierarchy to both TypeError type and ZeroDivisionError type.
Now running the code, to cut a pizza into 6 pieces results in something like this!
Please enter the Numerator: Pizza Please enter the Denominator: 6 You have entered zero as denominator
As you can see the ValueError exception bug is completely hidden due to our poor choice of Exception type.
Instead if you wrote your code like this using ZeroDivisionError
def divide(numerator, denominator): if (denominator == 0): raise ZeroDivisionError else: return int(numerator)/int(denominator) try: x = input('Please enter the Numerator: ') y = input('Please enter the Denominator: ') print(x, ' / ', y, ' = ', str(divide(x,y))) except ZeroDivisionError: print("You have entered zero as denominator")
Then if you run the code with bad values, the interpreter will crash the program revealing the ValueError bug as shown below.
Please enter the Numerator: Pizza Please enter the Denominator: 6 Traceback (most recent call last): File "", line 4, in print(x, ' / ', y, ' = ', str(divide(x,y))) File "", line 5, in divide return int(numerator)/int(denominator) ValueError: invalid literal for int() with base 10: 'Pizza'
Hence always go for the Exception type which is specific and appropriate for your situation!
raise and User-Defined Exception Types
Next let us see the best-practices to follow when raising user-defined Exception types. Let us start by learning how to make user-defined exceptions.
How to make your own exception?
In Python making your own exception type is super simple with just 2 lines of code
class MyException (Exception): pass
Just declare a class that inherits from the built-in Exception class. Then you can raise your exception using Syntax#1 as shown below
>> raise MyException('I am raising my own Exception!!!') Traceback (most recent call last): File "", line 1, in raise MyException('I am raising my own Exception!!!') MyException: I am raising my own Exception!!!
You can also use Syntax#2 as shown below
>> raise MyException Traceback (most recent call last): File "", line 1, in raise MyException MyException
When you should Raise your own custom-defined Exception types and when you should use built-in exceptions?
- avoid using user-defined Exception types if possible, as python built-in error types are designed to fit almost every use-case and user-defined Exception types can make the code harder to read and maintain.
- Make sure your exception classes inherit from an appropriate python built-in class
- Generic error are more likely to hide bugs and are considered bad programming practice hence try to go as specific as you can while choosing exceptions.
Let us next move onto the 3rd, final and even shorter syntax of using the raise statement.
raise Syntax#3: without any arguments
The third syntax is to just use the raise statement with no arguments as shown below.
Let us see an example to see how this can be used.
def reRaiseException(): try: raise ValueError('I am raising a value error for no reason') except ValueError as err: print('reRaiseException(): ', str(err)) print ('Re-Raising the exception to the calling code') raise try: reRaiseException() except ValueError as error: print('Main code: ', str(error))
Running this code will give an output like this
reRaiseException(): I am raising a value error for no reason Re-Raising the exception to the calling code Main code: I am raising a value error for no reason
Here in the function reRaiseException() a ValueError is raised (in Line3) with a custom message and caught by a except clause inside the function. In Line7 the caught exception is re-raised to the calling code.
The except clause in Line10 catches this exception and prints the custom error message passed first on Line3 inside the reRaiseException() function.
One point worth noting is that, if there was no except clause inside the reRaiseException() function, the exception would have been straightaway passed to the main code without the use of the line raise.
Try running the example code below to see what I mean
def reRaiseException(): raise ValueError('I am raising a value error for no reason') try: reRaiseException() except ValueError as error: print('Main code: ', str(error))
The output of the above code is
Main code: I am raising a value error for no reason
If there was no except clause to catch this one level up, then this exception will crash the program, same as Example 1 in the beginning of the article.
The main reason for the existence of this syntax is because, there are situations, where you might want to do something in the except block inside the reRaiseException() function but you wish to let the the calling code to actually handle that Exception.
In our case we merely printed out 2 more lines before reraising the exception to the main code to demonstrate this point. We will see examples of some situations where this might be useful later in this article.
If no exception is present in the current scope the interpreter will raise a RuntimeError exception indicating that this is an error. This can be easily demonstrated by typing raise and hitting the enter button on the python console.
Traceback (most recent call last): File "", line 1, in raise RuntimeError: No active exception to reraise
As you can see the interpreter prints an appropriate error message namely
No active exception to reraise
And that ends our 3rd and final syntax/variants of using the raise statement.
Exception Chaining and raise Statement
Before ending this article, I would like to point out there there are one more syntax that employ the raise statement. A very common use-case involves Exception Chaining.
This comes in 2 sub-variants as shown below.
raise <exception type 1> as <exception type 2>
raise <exception type 1> as None
This is an advanced topic which needs a separate article to explain. Exception Chaining is typically used in big projects with several layers of abstractions, each layer having a set of user-defined Exceptions.
First try and master the above 3 syntax, as those will be used more that 9 out of 10 times you will ever need to use the raise statement.
And with that I will end this article.
Hope you have enjoyed reading this article and got some value from it.
Feel free to share this article with your friends and colleagues.
Be sure to checkout my other article on Exceptions
which covers all the basics of exceptions and strategies to handle them!