In the previous lesson we wrote our function with its assertion in notebooks
. As we have discussed previously, it is much more useful to write these as a script which we can then call, or in the case of libraries import. In this lesson we will write our mean function as a script and revise how to display documentation and call the function. We will then explore how to include our own libraries within other scripts revise why it is good practice to include the main part of the script in its own function.
If you have not already created a directory my_testing
in your intro-testing
directory, do so and cd
into it. Then create a new file called mean.py
. You are free to use the editor of your choice, e.g. nano
or others on linux
, or use the notebooks text editor.
Note that this will not be available on remote linux machines so you should be confident to use editors like nano
if required.
Edit your new file mean.py
so that it reads:
def mean(sample):
'''
Takes a list of numbers, sample
and returns the mean.
'''
assert len(sample) != 0, "Unable to take the mean of an empty list"
for value in sample:
assert isinstance(value,int) or isinstance(value,float), "Value in list is not a number."
sample_mean = sum(sample) / len(sample)
return sample_mean
numbers = [1, 2, 3, 4, 5]
print( mean(numbers) )
no_numbers = []
print( mean(no_numbers) )
word_and_numbers = [1, 2, 3, 4, "apple"]
print( mean(word_and_numbers) )
Finally we can execute our script, you can do this form the terminal but we will run from within notebooks as we did before. in your library, navigate to the folder containing your mean.py
file and luanch a new notebook:
%run mean.py
You should see an output that looks like:
Traceback (most recent call last):
File "./mean.py", line 22, in <module>
mean(no_numbers)
File "./mean.py", line 10, in mean
assert len(sample) != 0, "Unable to take the mean of an empty list"
AssertionError: Unable to take the mean of an empty list
Our scripts executes each of line of code in turn and stops when it reaches the first AssertionError
, even though this is how we intend the program to execture, Python doesn't know this and it means that it does not yet run the third of our tests. We will learn how we can run multiple tests, and encapsulate them in successful tests even if they intentionally raise errors.
Now we want to explore our script in a little more detail. Remember in our previous lesson we import
ed libraries into our interactive session. Let's see what happens when we do this with our new script. Let's try to import mean.py
as a library:
import mean
3.0
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-1-330bb4995352> in <module>
----> 1 import mean
/home/rjg20/training/arc-training/intro-testing/mean.py in <module>
20 no_numbers = []
21
---> 22 print( mean(no_numbers) )
23
24 word_and_numbers = [1, 2, 3, 4, "apple"]
/home/rjg20/training/arc-training/intro-testing/mean.py in mean(sample)
8 '''
9
---> 10 assert len(sample) != 0, "Unable to take the mean of an empty list"
11 for value in sample:
12 assert isinstance(value,int) or isinstance(value,float), "Value in list is not a number."
AssertionError: Unable to take the mean of an empty list
What we would like to do is change the behaviour of our program so that the functions are available when it is imported, but the remainder of the scripts only executes when we run it from the command line. This is called limiting the scope of the script, open your script and edit it so that it reads:
def mean(sample):
'''
Takes a list of numbers, sample
and returns the mean.
'''
assert len(sample) != 0, "Unable to take the mean of an empty list"
for value in sample:
assert isinstance(value,int) or isinstance(value,float), "Value in list is not a number."
sample_mean = sum(sample) / len(sample)
return sample_mean
def main():
numbers = [1, 2, 3, 4, 5]
print( mean(numbers) )
no_numbers = []
print( mean(no_numbers) )
word_and_numbers = [1, 2, 3, 4, "apple"]
print( mean(word_and_numbers) )
if __name__ == '__main__':
main()
Now run this as a script and also try importing it in ipython. __name__
determines the scope of a script, if it is run as a script it is set to __main__
, but not when it is imported, allowing the behaviour to be different in the two cases. You can find out more here.