Using Python Try Else Finally

by James Johnson

Python’s exception handling mechanisms go beyond simple try and except statements. Using the else and finally clauses can make your life and code simpler.

Python Try-Except

To start off, when I (and others) are being lazy, I might write code like this:

try:
    do_something()
except Exception:
    pass

This is bad form. Exception classes should explicitly be caught. Even if it were logical to use the code above, the raised exception should probably at least be logged:

import logging
import traceback

logging.basicConfig(level=logging.DEBUG)
LOG = logging.getLogger("Example")

try:
    do_something()
except Exception as e:
    LOG.exception("Exception doing something!", exc_info=True)

Python Try-Finally

Sometimes I purposefully only use the try and finally statements without having any exception handlers. The most common use case for this is when I am dealing with temporary files or directories.

For example, suppose that I need to clone a git repository, do something with the cloned files, and then cleanup. I would typically use something like this:

import os
from sh import git
import shutil
import tempfile

def do_git_operations(tmpdir):
    project_url = "https://github.com/d0c-s4vage/vim-morph"
    repo_path = os.path.join(tmpdir, project_url.rsplit("/", 1)[-1])
    git.clone(project_url, repo_path)
    # do stuff with cloned repo (probably want to use git.bake() to
    # set the working tree

tmpdir = tempfile.mkdtemp()
try:
    do_git_operations(tmpdir)
finally:
    shutil.rmtree(tmpdir)

If this were a process I found myself doing fairly often, I would use the contextlib.contextmanager decorator to turn a function into a context manager that would take care of creating the temporary directories, cleaning up, etc. See my python-context-lib post for more details.

Python Try-Else

The else clause executes when the code within the try clause does not raise an exception. Why would you even need an else clause? Couldn’t you resume execution as normal within the try clause without needing it?

The purpose of the else clause is to allow you to be explicit about where the exceptions you are catching are coming from. The else clause is also useful for explicitly showing that statement(s) depend directly on the successful execution of code within the try clause.

For example, in the code below there are two statements in the try clause:

try:
    res = this_might_cause_exception()
    do_something(res)
except Exception as e:
    # do something useful here

Although I am originally only trying to catch exceptions raised by calling the this_might_cause_exception() function, the except block will also catch any exceptions raised by the do_something() statement. Ideally we would put the do_something() statement in the else clause to explicitly signify that calling do_something is directly related to the successful execution of the this_might_cause_exception() function:

try:
    res = this_might_cause_exception()
except Exception as e:
    # do something useful here
else:
    do_something(res)