uwhpsc-2016 / homework1

Homework #1
1 stars 1 forks source link

Raising Errors in Python #17

Open cswiercz opened 8 years ago

cswiercz commented 8 years ago

Mathematical Pop Quiz

Can you figure out why it's important to assert that n > 0 when calling collatz_step and collatz?

Why Raise Errors

Forcing your code to raise errors when a user provides incorrect or invalid input is a good way to protect users from performing invalid operations and ending up with gibberish output. This type of scenario ties in well with the code testing process, hence the two or so problems in this week's homework that ask you to implement exception raising.

Errors and Exceptions Tutorial

If you are interested in reading further I recommend taking a look at Errors and Exceptions in the Python tutorial. For the purposes of this class, I will describe below all that you need to know.

Suppose I have a function, foo(x) in a Python module mystuff.py where I want the function, and the user's whole program for that matter, to stop execution if the given x is equal to three. (For some reason or another, three is an invalid value.) I might write it like this:

# neatstuff.py

def foo(x):
    if x == 3:
        raise ValueError
    # rest of foo's code
    # ...

So if someone else's script, dothings.py looked like this:

# dothings.py

from neatstuff import foo
foo(3)
print 'All done.'

the following would occur when running dothings.py:

$ python runthings.py
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-2e3eac5304ba> in <module>()
----> 1 foo(3)

<ipython-input-2-d8da1e618e52> in foo(x)
      1 def foo(x):
      2     if x == 3:
----> 3         raise ValueError
      4 

ValueError: 

Note that 'All done' is never printed because the error caused the program to halt right then and there. The "traceback" above gives you some information on where the exception occurred.

Different Kinds of Errors

To help be more descriptive, there are different kinds of errors you can raise in Python. The reference page Built-In Exceptions has a full list. Some notable ones are:

for example, the following (silly) code tells a user when they have exceeded the bounds of an array

def get_element(arr, index):
    # arr is of type `list` or `numpy.ndarray`
    if (index < 0) or (len(arr) <= index):
        raise IndexError('Hey, bub. Your index doesn't work...')

Testing If a Function Raises an Error

Which finally leads me to the test in the test suite.

    def collatz_step_error(self):
        with self.assertRaises(ValueError):
            # some code

What this is doing is it's checking to see if whatever was written in for "# some code" raises an error of type ValueError. This is a useful kind of test to make sure that your code raises errors when it's supposed to so that your users understand what values ranges are appropriate and what aren't. If # some code ends up not raising an error then this test in the test suite will fail! Actually, it will fail even if it raises an error but the error is not of type ValueError.

Hopefully this little tutorial clarifies any confusion regarding exceptions and how to test for them.