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:
ValueError - raised when a function receives an argument that has the right type but an inappropriate value,
TypeError - raised when an operation or function is applied to an object of inappropriate type,
IndexError - raised when a sequence subscript is out of range
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.
Mathematical Pop Quiz
Can you figure out why it's important to assert that
n > 0
when callingcollatz_step
andcollatz
?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 modulemystuff.py
where I want the function, and the user's whole program for that matter, to stop execution if the givenx
is equal to three. (For some reason or another, three is an invalid value.) I might write it like this:So if someone else's script,
dothings.py
looked like this:the following would occur when running
dothings.py
: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:
ValueError
- raised when a function receives an argument that has the right type but an inappropriate value,TypeError
- raised when an operation or function is applied to an object of inappropriate type,IndexError
- raised when a sequence subscript is out of rangefor example, the following (silly) code tells a user when they have exceeded the bounds of an array
Testing If a Function Raises an Error
Which finally leads me to the test in the test suite.
What this is doing is it's checking to see if whatever was written in for "
# some code
" raises an error of typeValueError
. 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 typeValueError
.Hopefully this little tutorial clarifies any confusion regarding exceptions and how to test for them.