Error handling Python: part 4

You can detect errors in your code using if statements, as we did in the first post, or you can detect them using the try-except structure, as we did in the second and third posts. With both of these approaches, we used the print command to provide the user with some information about the error and the sys.exit() command to stop the program. In this, our last post on error handling in Python, we will learn how to raise exceptions and discuss when such an approach would be useful.

Raising exceptions

Raising an exception is simple. You just write raise E(message), where E is a known exception type (e.g., ValueError, TypeError) and message is text explaining what went wrong.

A simple example might look like:

x = input('Please enter two integer values between 0 and 10.')
try:
    numbers = x.split()
    number1 = int(numbers[0])
    number2 = int(numbers[1])   
except TypeError:
    raise TypeError('{} is not an integer'.format(x))
except IndexError:
        raise IndexError('Please provide 2 numbers, e.g. 43 5')   

On its own, this application of raise is not very useful. It would be more useful to use raise in the context of a function, such as verifying the input provided to our function by a user. Here is an example:

import sys

def read_weight_height():
    try:
        weight = float(sys.argv[1])    # in kg
        height = float(sys.argv[2])    # in meters
    except IndexError:
        raise IndexError('This program needs two inputs, weight (kg) and height (m). \nExample: python bmi_calc.py 75 1.7')
    except ValueError:
        raise ValueError('Weight (kg) and height (m) must be pure numbers.')
    if weight <= 0:
        raise ValueError('Cannot compute BMI for zero or negative weight, i.e. {} kg'.format(weight))
    if height <= 0:
        raise ValueError('Cannot compute BMI for zero or negative height, i.e. {} m'.format(height))

Great, we can now use this function as part of our program to test for various errors. However, the downside to this approach is that the output to the user is more complex. This is demonstrated below.

$ python bmi_calc.py

Traceback (most recent call last):
  File "bmi_calc2.py", line 7, in 
    raise IndexError('This program needs two inputs, weight (kg) and height (m). \nExample: python bmi_calc.py 75 1.7')
IndexError: This program needs two inputs, weight (kg) and height (m). 
Example: python bmi_calc.py 75 1.7

The solution is to call our function in a try-except structure. This gives us complete control of how our program handles errors and provides error-specific messages to the user. Here is what our final program looks like:

import sys

def read_weight_height():
    try:
        weight = float(sys.argv[1])    # in kg
        height = float(sys.argv[2])    # in meters
    except IndexError:
        raise IndexError('This program needs two inputs, weight (kg) and height (m). \nExample: python bmi_calc.py 75 1.7')
    except ValueError:
        raise ValueError('Weight (kg) and height (m) must be pure numbers.')
    if weight <= 0:
        raise ValueError('Cannot compute BMI for zero or negative weight, i.e. {} kg'.format(weight))
    if height <= 0:
        raise ValueError('Cannot compute BMI for zero or negative height, i.e. {} m'.format(height))
    return (weight, height)

try:
    weight, height = read_weight_height()
except Exception as e:
    print (e)
    sys.exit(1)
bmi = weight/height**2
print(bmi)

In the above code, we use Exception, the parent of all exceptions, and e, an exception object, to capture any exceptions that arise from using our read_weight_height() function. Don’t worry if you don’t fully grasp Exception and e, just copy this approach and you will always capture errors and provide informative error messages.

Now let’s see what happens when we use our function:

$ python bmi_calc.py
This program needs two inputs, weight (kg) and height (m). 
Example: python bmi_calc.py 75 1.7

$ python bmi_calc.py 44
This program needs two inputs, weight (kg) and height (m). 
Example: python bmi_calc.py 75 1.7

$ python bmi_calc.py 44kg 1.6m
Weight (kg) and height (m) must be pure numbers.

$ python bmi_calc.py -1 1.6
Cannot compute BMI for zero or negative weight, i.e. -1.0 kg

$ python bmi_calc.py 78 0
Cannot compute BMI for zero or negative height, i.e. 0.0 m

$ python bmi_calc.py 78 1.6
30.468749999999993

Conclusion

Well, we are done with our short series on error handling in Python. Hopefully you learned a thing or two along the way and will consider using some of these concepts in your next coding project.

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