Python Friday #12: Exceptions

When you start learning a new programming language, you will first fight a lot with the syntax. Before you even can run your program you already get an error that you need to fix. After a while those syntax errors get less and less, and you can focus on creating a working application.

You quickly realise that valid Python syntax is not enough, your code must be able to handle wrong user input, missing resources or network errors. You now entered the endless challenges of creating a robust application and exceptions (and their handling) are an important part of it.

This post is part of my journey to learn Python. You can find the other parts of this series here.

 

What are exceptions?

I think of exceptions as exceptional cases that cannot be handled in your application. That can be a simple division by 0 or missing permissions to create a file.

If we execute this code, we get an exception and a stack trace, because a division by 0 has no mathematical solution:

This tells us that on line 5 we call a function that throws a ZeroDivisionError exception on line 2. The last part of a stack trace is often the most important one, so you should always start at the end to find out what went wrong.

 

Basic exception handling

With the try: statement we can tell python that we want to handle the exceptions for the next block by ourselves. If we rewrite the divide function like this, Python will print out a nice error message instead of a stack trace:

To check if we get our error message or a stack trace, we can simply call our method again:

 

What exception was it?

While in most cases we are happy to prevent an exception from crashing our application, we sometimes need to know what exactly went wrong. Wit a little change we can get the raised exception and find out more about the problem:

If we run our code now, we see that the division by zero is the problem:

If we enter a string, the error changes:

 

Handle the individual exceptions

As you can see in the examples above, the exceptions have different classes. We can now prevent the most common problems and return a useful error message instead of crashing our application:

This change in our code gives us a much better user experience when something goes wrong:

There is a little catch you need to be aware of: When an exception occurs, the exception handler searches for an except clauses until one is found that matches the exception – including any parent in the inheritance hierarchy. This means, the first match wins. Therefore, if your first except clause is for Exception, it will be used and the more specific exception that you wrote after it will be ignored.

Airbrake.io has a good explanation of the class hierarchy for exceptions in Python.

 

Clean-up if an exception occurs or not

Sometimes you have code that should always be executed, regardless of whether an exception has occurred or not. This is especially helpful when you need to clean up resources or close files. Code like that goes into a finally clause at the end of your except blocks:

Every call to the divide method will now end with the line “runs always”:

 

Raising exceptions in your code

We can raise an exception by using the raise keyword and then use the exception class that fits our needs:

If we call our code with a number, everything works. However, when we use a string as an argument it crashes with an exception:

 

Creating your own exceptions

We can make our own exceptions by creating a subclass of the Exception class:

We can use our CustomError exception like any other exception:

If you want to know more about custom exceptions you should read this short article from Programiz.

 

Conclusion

Exceptions are an important concept of programming and a necessity to create robust code. Luckily for us, they are easy to use in Python.

1 thought on “Python Friday #12: Exceptions”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.