Functions and Modules

See also

Text, Chapter 8

Read time: 25 minutes (6371 words)

We introduced Functions earlier in the course, since the concept of packaging a block of code we can use over and over is critical to programming. In this section, we will complete our discussion on functions and show how to package them into a useful form we really can use in other programs. The form is called a module.

Reviewing the function

As you recall, a function is a block of code that we give a name. That block can have parameters, which provide data for the function to work with, and it can return a value to whatever code called it. Both parameters and return values are optional.

Here is a simple function, demonstrating all the parts:

def adder(val1, val2):
    sum = val1 + val2
    return sum

We can call this function from any chunk of code that can see the definition. You should review the lecture on scope to make sure you can identify where the function can be called.

Here is some code that will work:

print("The sum of 5 and 7 is",adder(5,7))

In this statement, we are calling another function, print, which is being handed two parameters. The first is a string, and the second is a call to our adder function. Python will halt processing or the print function, and call the adder function. When that function returns, Python will hand that value to the print function so it can display the results.

Here is what we see if we test this in the Python interpreter:

>>> def adder(val1, val2):
...    sum = val1 + val2
...    return sum
...
>>> print("The sum of 5 and 7 is",adder(5,7))
The sum of 5 and 7 is 12

Looks like it worked!

Note

Do any of you see something interesting about how print works? It seems that it can take a different number of parameters, depending on what we want to print. We will see how to do this later.

What would happen if we ran this code:

adder(7,9)

Actually, Python would call the function and get the result back. However, since we are not doing anything with the returned value, it is just discarded!

Returning multiple values

In some cases, you might want to create a function that returns more than one value. Python supports this as long as you do things properly. Here is a (way too) simple example:

def funny():
    return 5,7

a,b = funny()
print(a,b)

Running this gives:

>>> def funny():
...     return 5,7
...
>>> a,b = funny()
>>> print(a,b)
5 7

How about this:

>>> print("The sum of 5 and 7 is",adder(funny()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: adder() takes exactly 2 arguments (1 given)

Phooey! That did not work, but this does:

>>> a,b = funny()
>>> print("The sum of 5 and 7 is",adder(a,b))
The sum of 5 and 7 is 12

The funny function is returning multiple values, so we need to identify multiple places to put the results. Later we will see that Python supports a special kind of data container that can hold a bunch of values. It is called a list, but we are not ready for that yet.

Creating a module

A module is a file containing variables and functions we can use in other parts of a Python program. We have been using modules whenever we import something into our program, like when we used the sqrt function contained in the standard Python math module. What we want to do now is to figure out how to build our own module. We will do this by writing a super simple version of math called mymath. This module will do only two things, define a value for PI and figure out the trigonometric sine of an angle expressed in degrees. (The real math module wants angles in something called radians which are hard for people to figure out until you take a trig class! (Or work this week’s lab assignment!)

Start off by building a directory to hold the test code we will produce in this lecture:

C:\COSC1336> mkdir modules
C:\COSC1336> cd modules
C:\COSC1336\modules>

To build our module, we start off by creating a new file, mymath.py, that looks like this:

# mymath - a simple trig module

PI = 3.1415926

def sin(angle):
    return 0

if __name__ == '__main__':
    print("Testing the mymath module")
    print("The sin of 30 should be 0.5, and we get")
    print(sin(30))
    print("If this is not right, we have more work to do on this module!")

Note

That last chunk of code is a common pattern in Python modules. If we import mymath into another program, Python will ignore the code at the end and you will see no output from that code. If, however, you ask Python to process the module file directly (using python mymath.py), then Python will process the code t the bottom and you will see the test output you placed there. This is handy when developing the module.

Let’s test our new module by asking Python to run the module file:

python3 mymath.py
Testing the mymath module
The sin of 45 should be 0.5, and we get
0
If this is not right, we have more work to do on this module!

It looks like we have more work to do.

Setting up a better test

Since we are trying to build a function that works something like the real math module, let’s use that real module to test our new one. Sounds silly, but it will work:

# mymath - a simple trig module
import math

PI = 3.1415926

def sin(angle):
    return 0

if __name__ == '__main__':
    angle = 30.0
    radians = math.pi * angle/180.0

    print("Testing the mymath module")
    print("The sin of",angle, "should be",math.sin(radians), "and we get")
    print(sin(angle))
    print("If this is not right, we have more work to do on this module!")

Look closely at how this code is set up. We have not really changed the module code, but we have changed the test code at the bottom. Testing the module will help us know when we have our module code written correctly (at least for one case). We will do a better job of testing later.

Referencing module names

Do you see how we referenced named from the real math module? In this example, we only imported the name of the module. In order to access the names in that module, we use modulename.name notation. In the math module we can access a better value for PI by using math.pi and get the real sin function using math.sin. Remember how we used the sqrt function in the math module earlier:

from math import sqrt

x = sqrt(5)

In this code, we used a different form of import. This form specifically makes a single name(in this example) available without needing to add the module name to the front. You choose which approach you like better.

There is another form we can use:

from math import *

x = sqrt(5)

In this form, we ask Python to make all names defined in the module available to the program file with this import line.

Note

If you want to see all the names a module has in it, you can do this from the Python interpreter:


>>> import math
>>> dir(math)
['__doc__', '__file__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh',
'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf',
'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum',
'gamma', 'hypot', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10',
'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']

Boy, that is a lot of math stuff!

How does Python find modules

For our experiments, Python is finding our mymath module by looking in the current directory (where you are working) for the file mymath.py. If it fails to find it, it also looks in standard places in the Python distribution on your systems. We will see how this is done a bit later in the course. The math module is a bit different, since Python, itself, is written in C++, and most of the math routines are part of that language. Other standard modules that come with Python are found in lives in c:\Python33\Lib. There are good references to the tools found there. My favorite is Doug Hellmann’s Python Module of the Week found at http://www.doughellmann.com/PyMOTW.

We will learn a bit more about modules are we work through the rest of the course!

Using your module

We have enough code in mymath.py to show how to use it. Let’s create a test program in test.py:

# test.py - a program that uses our mymath module
import mymath

def main():
    print("Testing mymath")
    sinx = mymath.sin(30.0)
    print("The sin of 30 degrees is", sinx)

main()

In this version, we did not import the names, so we need to use the module.function form to call the new function. We could have done this instead:

# test.py - a program that uses our mymath module
from mymath import sin

def main():
    print("Testing mymath")
    sinx = sin(30.0)
    print("The sin of 30 degrees is", sinx)

main()

We need to be careful if we try to import two modules that provide the same functions. If we imported the tried to import the sin function from both math and mymath Python would not be able to figure out which is which:

The solution is to use the module.name approach for one or both. This would work:

# test.py - a program that uses our mymath module
import mymath
from math import sin

def main():
    print("Testing mymath")
    sinx = mymath.sin(30.0)
    print("The sin of 30 degrees is", sinx)
    print("Python says the sin of 30 degrees is", math.sin(30*math.pi/180.0))

main()

In that last line I an converting degrees into radians (we will look at that in this week’s lab) before handing the result to the math sin function.

Phew!