Advanced Compound Statements

Let’s explore some of Python’s more advanced key words and statements!

Try / Catch / Finally

The “Try-Catch” statement exists in many languages and got its primary influence from Java. In Python, it’s called a “Try-Except” statement. It’s used to catch exceptions.

Of course, you’ve seen many examples of exceptions before.

>>> 1 / 0
ZeroDivisionError: integer division or modulo by zero

Here is a perfect example of an exception – a ZeroDivisionError exception. Let’s write a function to catch the exception. When you catch an exception, rather than crashing as usual, the program instead follows your code. This way, you can have the program do cool things instead of just exiting suddenly.

function cool_divide():
    '''
    Asks the user for inputs and divides them repeatedly.
    Stops when user enters 'q' as an input.
    '''
    user_input = '1;1'
    while user_input != 'q':
        user_input = raw_input("Enter two numbers to divide in the format 'a;b': ")
        if user_input == 'q':
            break
        
        numerator, denominator = user_input.split(';')
        numerator, denominator = float(numerator), float(denominator)
        print '%f divided by %f is %f' % (numerator, denominator, numerator / denominator)

So far so good; nothing mind-bendingly crazy. Now, we could use if statement to check whether numerator or denominator are 0 rather than a try-except statement, but this will be more fun, as you’ll soon see.

So how do we add the try-except statement? Like this:

try:
    print '%f divided by %f is %f' % (numerator, denominator, numerator / denominator)
except ZeroDivisionError:
    print 'Cannot divide by zero!'

So now, whenever it encounters a ZeroDivisionError exception, rather than quitting like it did above, it will print 'Cannot divide by zero!' instead! Of course, you could make it do anything you wanted.

There is actually a third (optional) part to the try-except statement called finally. The code under the finally statement is executed either way – that is, whether there is an exception or not. Let’s use that, too.

try:
    print '%f divided by %f is %f' % (numerator, denominator, numerator / denominator)
except ZeroDivisionError:
    print 'Cannot divide by zero!'
finally:
    print "Let's try again with new numbers. Or, enter 'q' if you would like to quit."

Now, whether or not there was an exception, the bottom string will be printed. Try statements are far more flexible ways of catching exceptions. As you can imagine, all exceptions stem from one super Exception class, so this way a few except statements can catch all possibilities of errors and react accordingly, rather than using numerous if statements to check for every possibility of something going wrong.

For example, if you wanted to catch every exception ever, you would simply use except Exception: instead of except ZeroDivisionError:.

With Statement

The with statement was introduced in Python 2.5 as a “context manager”. Now that you know try / except / finally statements, you can understand the with statement more concisely. Here are two pieces of code that are equivalent.

def controlled_execution(callback):
    set things up
    try:
        callback(thing)
    finally:
        tear things down, or clean up code

def my_function(thing):
    do something

controlled_execution(my_function)

You’ve seen functions being passed as parameters plenty of times, and this is yet another example. Let’s say you had to do some set up and tear down every time before and after your function was called. You could use a try / finally statement to do this.

Unfortunately, that’s a little too verbose for the Python style. So Python lends a hand. Here is the with statement version:

with controlled_execution() as thing:
    some code

Wow! Way better. The classic example of a context manager is using files. Every time you read from a file, you have to open it (before your function) and close it (after your function). Here is the usual way.

f = open('some_file.txt')
lines = f.readlines()
f.close()

But this can be dangerous; sometimes we forget to close the file, sometimes other things happen. There has to be an easier way!

with open('some_file.txt') as f:
    lines = f.readlines()

That’s it! Pretty useful, huh?

Context managers mean that you should only be using try / except statements to catch exceptions; in all other cases, context managers should be used instead!