In this article, let us take a walk-through of the Exception class in Python and see what useful methods and attributes they present to us and learn how we can utilize them in our code.
The Exception class in python acts as the parent class for most of the exceptions we deal on a day to day basis. It is carefully constructed by the python developers and includes several methods.
If you create a custom exception, these methods will automatically be included since you would be inheriting it from the Exception class or one of its subclasses. And as a good developers, it is our responsibility to have a good knowledge about all these methods. And that is why I’ve compiled all these methods in one single article.
Lets
- first start with the documentation that comes with python for the Exception class.
- then have a look at each method individually with the help of some examples.
If you are interested in a specific method, you can jump to it using the table of contents below
Exception Class: Documentation
The screenshots below shows documentation.
The 1st screenshot below shows that the exception class inherits from the BaseException class and it also shows the 2 main methods that are defined in this class, the __init__ and __new__ methods.
The second screenshot below shows the methods that are inherited from its parent class BaseException
The 3rd and last screenshot below shows the Data descriptors that are inherited from the BaseException class.
You can also view all these on documentation right from your Python interpreter terminal by using the line of code below
>>> help(Exception)
The inbuilt function help is very useful in reading the documentation of any class and its methods in Python.
So in total there are 10 methods
- __delattr__
- __getattribute__
- __reduce__
- __repr__
- __setattr__
- __setstate__
- __str__
- with_traceback
- __init__
- __new__
and 6 data descriptors
- __cause__
- __context__
- __dict__
- __suppress_context__
- __traceback__
- args
Almost all the above methods are called “dunder” methods, which is short for “double underscores“. You can easily recognize a dunder method; they always have two prefix and suffix underscores in the method name.
Dunder methods are also known as Magic methods as they are responsible for lot of important work and they work silently in the background.
Most of these dunder methods in the list above are actually common with all the python classes, and some of them don’t do anything extra-special in the context of usage with Exception class.
Only the below 2 methods can be used to make our code cooler while working with the Exception class.
- __init__() method
- with_traceback() method
Coming to the data descriptors, the ones listed below actually contain a lot of useful information, we will see how we can utilize them a bit later in the article.
- args
- __context__
- __traceback__
Let’s start with the simplest __init__ method
__init__()
The __init__ method is a very simple method, it is called every time an object is created and it is present in all python classes.
It is used to initialize the attributes of an object. It is basically what we call “a constructor“, it takes in arguments and assign them to the data members of the class.
In the context of the Exception class, one common way to wield the power of __init__ method is to pass to it the message that we wish to print in case of errors.
For example:
>>> x = Exception()
>>> raise x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception
In the code above I have
- created an Exception object x (this will call the __init__ method in the background with no arguments)
- raise the newly created exception object.
Once raised, the traceback is printed and if you look carefully, the last line just says “Exception“
If you are wish to master the usage raise statement, I suggest setting aside 15mins for the article below
Python: Manually throw/raise an Exception using the “raise” statement
You can easily customize this line by passing in an argument to the __init__ method as shown below
>>> x = Exception()
>>> x.__init__("Fancy Error Message")
>>> raise x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: Fancy Error Message
You can also get the same end result with the code below and let the magic method __init__ do its thing in the background for you!
>>> x = Exception("Fancy Error Message")
>>> raise x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: Fancy Error Message
Here the passed in error message gets stored in the args attribute.
The error text actually contains a lot of useful information if we look at it from the right perspective. We have an entire article on the topic of “how to read the error messages like a pro”, where we discuss the parts of an error message and how we can use them to debug our code. You can find that article in the link below.
Python: Details contained in an Exception
args
This data descriptor is basically the arguments that gets passed in when we create an Exception object.
You can utilize them in a cool way as shown in the example below.
>>> x = Exception("Fancy Error Message")
>>> x.args
('Fancy Error Message',)
>>> raise x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: Fancy Error Message
>>> x.args = ('New Fancy Message',)
>>> raise x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <module>
Exception: New Fancy Message
In the code above, we
- created an Exception object, with “Fancy Error Message”
- then we raised it and we got the same error message
- then we simply changed the message it prints to “New Fancy Message”
- raised x again and we got the new message printed.
We can also create a new object with the new message instead if we need to change the message, which is actually the preferred way of doing this.
The above example is just to help you understand the part “args” play in the context of Exception class.
Alright, its time to move on to the next method, the with_traceback() method!
with_traceback()
The with_traceback method is a handy tool when you are dealing with exceptions.
Lets look at an example to see how this method can be used.
Here we simply catch and raise the exception object.
try:
1/0
except Exception as e:
raise e
OUTPUT
Traceback (most recent call last):
File "main.py", line 4, in <module>
raise e
File "main.py", line 2, in <module>
1/0
ZeroDivisionError: division by zero
As you can see in the output we have information about
- exception caused in line-2 (where we divided by 0, which is not allowed in math)
- exception raised by us in line-4
The 1st part is the traceback of the exception object when it was caused in line-2, when we raised again in line-4 the traceback of the exception object e got appended with the information about line-4.
Say instead of appending the traceback object, you wish to give it some context instead so that you can get the following output.
See how we have 2 Tracebacks instead of one, with the separator “During handling of the above exception, another exception occurred: “
Traceback (most recent call last):
File "to_delete.py", line 2, in <module>
1/0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "to_delete.py", line 5, in <module>
raise my_exception
File "to_delete.py", line 2, in <module>
1/0
Exception: An error occurred
This can be achieved with the help of the with_traceback() method as shown below.
try:
1/0
except Exception as e:
my_exception = Exception("An error occurred").with_traceback(e.__traceback__)
raise my_exception
Hence, the with_traceback() method can help us pack the __traceback__ of one exception object into the __traceback__ of another exception object , so that we can get more information while debugging the issue.
Speaking of __traceback__, that’s our next topic of dicussion!
__traceback__
As we saw in the previous example, the traceback object contains all the information that is collected when an exception occurs.
To print the information out we can use the following code
import traceback
try:
1/0
except Exception as e:
print(traceback.format_tb(e.__traceback__))
OUTPUT
[' File "to_delete.py", line 4, in <module>\n 1/0\n']
In order to effectively parse the information from the __traceback__ object, we need to make use of the functions that are available in the traceback module, which was imported in line-1.
Then the format function is used to parse out the information in the __traceback__ object which is basically a list of strings as shown above.
It is worth mentioning that this is not the only way to parse information from the __traceback__ object. The 3 articles linked below show how you can parse out specific pieces of information from the traceback and print them out.
Python: Printing Exception Type
Print just the message of an exception
Python: Print StackTrace on Exception!
The traceback module has several more interesting functions to use, I suggest you check them out over at python.org
__context__
To understand __context__ lets look at the example below.
try:
try:
try:
1/0
except Exception as e1:
my_e1 = Exception("Error1 occurred").with_traceback(e1.__traceback__)
print(f"e1.__context__ = {e1.__context__}")
raise my_e1
except Exception as e2:
my_e2 = Exception("Error2 occurred").with_traceback(e2.__traceback__)
print(f"e2.__context__ = {e2.__context__}")
raise my_e2
except Exception as e3:
print(f"e3.__context__ = {e3.__context__}")
Here we have
- 3 levels of try/except blocks
- each level makes an Exception object using the __traceback__ of the caught exception.
- prints out the context and
- raises the freshly baked exception.
This code will produce the following output.
OUTPUT
e1.__context__ = None
e2.__context__ = division by zero
e3.__context__ = Error1 occurred
As you can see, __context__ simply stores what happened one level above in the try/except blocks.
To expand
- The exception object e2 was raised in the context of “division by zero” exception and
- The exception object e3 was raised in the context of “Error1 occurred” exception (my_e1)
I hope you got the point!
As mentioned, the other methods of the exception class are common to all other classes, simple googling of the method name should get you the necessary details!
- __delattr__
- __getattribute__
- __reduce__
- __repr__
- __setattr__
- __setstate__
- __str__
- __new__
If you wish to learn about some method or data member that is not address in this article you can do so from the python.org documentation on the traceback topic
For the next step in your Python journey I invite you to master some of the most common errors you will run into in your daily life as a Python developer. We have compiled a list of just 7 exceptions that you need to focus on if you wish to gain mastery of Exceptions in Python!
7 Most Common In-Built Exceptions in Python!
If you are a visual learner here is a YouTube video that we made on that same topic!
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: Details contained in an Exception
Python: Printing Exception Type
Print just the message of an exception
Python: Print StackTrace on Exception!
Thanks to Namazi Jamal for his contributions in writing this article!