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!