Just click on the cell below if you want to see the images in codeblocks that say "Image(...)".
from IPython.display import Image
import os
Learn about functions
Discover the joys of modules
You can imagine that there are many bits of code that you'll want to use over and over again. For example, in Python the trigonometry functions require radians, but we Earth Scientists typically think in terms of degrees. It would be helpful to convert back and forth between degrees and radians. Or, you might want to find the great circle distance between two points on Earth, or convert between Universal Transverse Mercator (UTM - a special map projection with units of meters) and the more familiar latitude and longitude coordinates. This is where Python functions are come in handy. You can define a bit of code, assign it a name and a list of input arguments, and then keep re-using it anytime you like. Or, you can save it to a file in your Python code directory (see Lecture 1) and import it into any notebook or command line script any time you like.
We've already used built-in functions, for example list( ), which takes a list generator as an argument and then makes an actual list_ out of it. Now it is time to learn how to write your own functions.
The most common structure of a Python function is to supply some input (IN), do something to the input (RULE), then return the output (OUT).
Image('Figures/function-machine.png')
Here is an example of a Python function:
def FUNCNAME(in_args):
"""
DOC STRING
"""
out_args=in_args # ok - not very fancy....
return out_args
def FUNCNAME(in_args):
def
FUNCNAME
in_args
:
"""
DOC STRING
"""
The line or lines between the triple quotes right after the function definition line is a doc string. Here you write a description of what the function does, which can be accessed later by using the by now familiar help( ) function.
help(FUNCNAME) will print out the doc string.
Make a habit of using the doc string to explain what the function does. It is most helpful to have an explanation of what the input arguments are (type of object and what it is for) and what the returned objects are.
___________________________
The body of the function does something.
There is an optional return statement that can return the results of whatever the function did.
help(FUNCNAME)
Help on function FUNCNAME in module __main__: FUNCNAME(in_args) DOC STRING
Although you can certainly write functional code without a document string, make a habit of always including one. Trust me - you'll be glad you did and anyone using your code will be super grateful for any hints you give. The Doc String briefly describes what the code does; weeks after you've written your code, it will remind you of what you did. In addition, you can use it to print out a help message that lets others know what the program does. You should define what the input and output variables are and what the function does. I like the form:
""" This function doesn't do much.
Parameters:
in_args : str
The input string
Returns:
out_args : str
The output string (in this case the same as the input string).
"""
To make this point a little more clearly, you will LOSE POINTS ON YOUR HOMEWORK IF YOU DO NOT PUT DOC STRINGS INTO YOUR FUNCTIONS. Ok, that is a bit hard ball, but it will help you make good programming habits.
Notice the use of the triple quotes before and after the documentation string - this means that you can write as many lines as you want.
This is equivalanet to the body of the cartoon function labeled 'RULE'. This part of the function code must be indented, just like in a for loop, or other blocks of code.
The code can be as simple as pass which does nothing. Our example function just assigns the variable $in\_args$ to a new variable name $out\_args$.
Python separates the input and output arguments. Incoming arguments are passed in through the def statement ($in\_args$ in the example function) and returning arguments get shipped out with the return statement, which is the equivalent of the 'OUT' arm in our cartoon function. In the example function, $out\_args$ gets returned to the caller.
So, let's try it out:
# this calls the function with the input variables, in_args
print (FUNCNAME('Four'))
# or alternatively:
returned_value=FUNCNAME('Four')
print (returned_value)
Four Four
There are many more sophisticated possibilities, but for now, here is a simple one with
no input arguments, just a return statement:
def gimmepi(): # define the function
"""
returns the value of pi
Parameters:
____________
None
Returns:
___________
The value of pi
"""
return 3.141592653589793
print (gimmepi())
twoPi = 2*gimmepi()
print (twoPi)
3.141592653589793 6.283185307179586
And let's try out the help function for more practice:
help(gimmepi)
Help on function gimmepi in module __main__: gimmepi() returns the value of pi Parameters: ____________ None Returns: ___________ The value of pi
There are three different ways to pass arguments into a function:
This function has only one argument:
def degrees_to_radians(degrees):
"""
converts degrees to radians
Parameters:
___________
degrees : float
degrees to convert to radians
Returns:
________
radians : float
degrees converted to radians
"""
radians=degrees*gimmepi()/180.
return radians
print ('42 degrees in radians is: ',degrees_to_radians(42))
42 degrees in radians is: 0.7330382858376184
You do this by putting *args at the end of the list of required arguments if any.
def print_args(*args):
"""
prints argument list
Parameters:
____________
*args : tuple of input arguments
Returns:
________
None
"""
print (args) # args is a tuple that you can step through (like a list)
print ('You sent me these arguments: ')
for arg in args: # steps through the argument tuple
print (arg)
print_args(1,4,'hi there')
print_args(42)
(1, 4, 'hi there') You sent me these arguments: 1 4 hi there (42,) You sent me these arguments: 42
Notice how the arguments are actually passed as a tuple.... (One very common use of tuples).
def print_keyword_arguments(**kwargs):
"""
prints keyword argument list
Parameters:
_____________
**kwargs : dict
input dictionary of arguments
Returns:
________
None
"""
print (kwargs) # kwargs is a dictionary with key:value pairs
for key in kwargs:
print (key, kwargs[key])
print_keyword_arguments(arg1='spam',arg2=42,arg3='ocelot')
# ocelot is another Monty Python joke about Brian (from Life of Brian) trying to
# sell "Larks' tongues, Otters' noses and Ocelot spleens. yummy.
{'arg1': 'spam', 'arg2': 42, 'arg3': 'ocelot'} arg1 spam arg2 42 arg3 ocelot
It is considered good Python style to treat your main program block as a function too. This helps with using the document string as a help function and building program documentation in general. In any case, I recommend that you just start doing it that way too. In this case, we have to call the main program with the final (not indented) line
main( )
See how it is done in the following:
def print_keyword_arguments(**kwargs): # same function as before
"""
prints keyword argument list
Parameters:
_____________
**kwargs : dict
input dictionary of arguments
Returns:
________
None
"""
for key in kwargs:
print (key, kwargs[key])
def main(): # new function called "main"
"""
calls function print_kwargs
"""
print_keyword_arguments(arg1='spam',arg2=42,arg3='ocelot')
main() # runs the main program
arg1 spam arg2 42 arg3 ocelot
Notice how all the functions precede the main( ) function. This is because Python is not compiled and executes things in order. All of the functions and variables must be defined before they're called, otherwise the interpreter won't recognize them.
You may wonder how we've called functions (e.g., str( ), int( ), and float( )) that we did not define in our script. These are more built in Python functions that are accessible to every Python script.
What if you wanted to use functions that are defined in a different script written either by future you or by some other helpful soul?
You can define many functions in a separate script called a module, and import that script into your current script. Then you can call those functions in the module from within your program.
So let's say I put some functions in a file called myfuncs.py. To do this, we can use the %%writefile magic Jupyter notebook command you learned about in Lecture 1.
%%writefile myfuncs.py
## module myfuncs
def gimmepi():
"""
returns the value of pi
Parameters:
____________
None
Returns:
___________
The value of pi
"""
return 3.141592653589793
def degrees_to_radians(degrees):
"""
converts degrees to radians
Parameters:
___________
degrees : float
degrees to convert to radians
Returns:
________
radians : float
degrees converted to radians
"""
radians=degrees*3.141592653589793/180.
return radians
def print_args(*args):
"""
prints argument list
Parameters:
____________
*args : tuple of input arguments
Returns:
________
None
"""
print ('You sent me these arguments: ')
for arg in args:
print (arg)
Writing myfuncs.py
By the way, there are many so-called magic commands available in a Jupyter notebook. For a complete list, just type:
%lsmagic
Available line magics: %alias %alias_magic %autoawait %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode Available cell magics: %%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%js %%latex %%markdown %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile Automagic is ON, % prefix IS NOT needed for line magics.
Now you can import myfuncs, which will make all your hard work available to you in your notebook. To access a particular function, use the syntax module.function( ). Here is an example:
import myfuncs # this will import your module
myfuncs.gimmepi() # this just runs the gimmepi() function.
3.141592653589793
And some other things become possible like getting the document string. You can use help( ) as before, or you can get the doc string this way:
print (myfuncs.print_args.__doc__) # note that the __ is actually two underscores - not one
prints argument list Parameters: ____________ *args : tuple of input arguments Returns: ________ None
TIP: One thing that you might want to do is modify a module you are writing and then re-import it. This used to be possible with a built-in function reload( ). But now we have to import reload from the module importlib like this:
from importlib import reload
Now you can change your myfuncs.py module and reload it like this:
%%writefile myfuncs.py
## module myfuncs
def gimmepi():
"""
returns the value of pi
"""
return 3.141592653589793
def degrees_to_radians(degrees):
"""
converts degrees to radians
"""
return degrees*3.141592653589793/180.
def print_args(*args):
"""
prints out argument list
"""
print ('The arguments were: ')
for arg in args:
print (arg)
Overwriting myfuncs.py
reload(myfuncs)
help(gimmepi)
Help on function gimmepi in module __main__: gimmepi() returns the value of pi Parameters: ____________ None Returns: ___________ The value of pi
Inside a function, variable names have their own meaning which in many cases will be different from outside the calling function. So, variables names declared inside a function stay in the function.
def LasVegas():
V=123
def main():
LasVegas()
print (V)
main()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-19-43b89960ac32> in <module> 4 LasVegas() 5 print (V) ----> 6 main() 7 <ipython-input-19-43b89960ac32> in main() 3 def main(): 4 LasVegas() ----> 5 print (V) 6 main() 7 NameError: name 'V' is not defined
What happened in LasVegas stayed in LasVegas because V was defined in the function and doesn't exist outside.
This is true unless you declare a variable to be global. Then it is known outside the function.
Here is an example in which the main program "knows" about the function's variable V.
def SanDiego():
global V
V=123
def main():
SanDiego()
print (V)
main()
123
oops - what happened in SanDiego didn't stay in San Diego.
In addition to writing your own functions, modules, and programs, Python has many built-in functions and modules that you can import. We already encountered a few built in functions (for example int( )) but there are many more. And there are many more modules which we will use shortly. We'll spend the quarter exploring some of these modules, which include plotting, numerical recipes, trig functions, image manipulation, animation, and more.
# a little housekeeping
os.remove('myfuncs.py')