Python language basics 62: clean-up after exceptions with finally

Introduction

In the previous post we discussed how to re-raise an exception using the raise keyword. You can use “raise” in order to re-throw the most recent exception with all its details so that it’s not silently suppressed or replaced with another exception which lacks the necessary details in order to locate bugs.

In this post we’ll see how to run a code block irrespective of whether an exception was raised or not.

The finally keyword

The finally keyword can be used in conjunction with try and except. The code block in finally is always executed even if an exception is thrown. Very often the finally block is used in order to restore some state that might have been altered in the try block.

Probably the most common example is file handling. Opening and reading from or saving to a file is considered as error-prone operations: the file might not exist, the caller may not have the necessary access, the file may be corrupted etc. So at some point your code in the try-block will throw an exception leaving the file still open, unsaved or some other undesirable state. The purpose of the finally-block is that the code within it will always run no matter whether the code in the try block threw an exception. Therefore you can always be sure that any code which restores some state will be executed.

The finally block can be used with or without an except-block. Consider the following version of the code from the previous post:

def divide(first, second):
    res = 0
    try:
        res = first / second
    except ZeroDivisionError:
        print("Big NONO")
        raise
    return res

try:
    res = divide(10, 2)
    print(res)
    print("I am here.")
finally:
    print("This statement is always executed.")
    print("...and this one as well.")

Note how the try-block is followed by the finally-block and the except-block is omitted. Running the above code will produce the following output:

5.0
I am here.
This statement is always executed.
…and this one as well.

There was obviously no exception thrown and the finally block was executed normally.

If we call the divide function as follows…:

try:
    res = divide(10, 0)
    print(res)
    print("I am here.")
finally:
    print("This statement is always executed.")
    print("...and this one as well.")

…then we get the following output:

Traceback (most recent call last):
Big NONO
File “C:/PythonProjects/HelloWorld/Various.py”, line 11, in
This statement is always executed.
res = divide(10, 0)
…and this one as well.
File “C:/PythonProjects/HelloWorld/Various.py”, line 4, in divide
res = first / second
ZeroDivisionError: division by zero

Note that the exception raised by the divide function was not caught but the finally-block was still executed.

Here’s how you can pair up the except and finally blocks:

try:
    res = divide(10, 0)
    print(res)
    print("I am here.")
except Exception as err:
    print(type(err))
    print(err.args)
    print(err)
finally:
    print("This statement is always executed.")
    print("...and this one as well.")

This will produce the following output:

Big NONO

(‘division by zero’,)
division by zero
This statement is always executed.
…and this one as well.

Read the next post here.

Read all Python-related posts on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: