Tutorial, Part 2: Functions and modules, focus on numpy

Contact: compwiki@physics.utoronto.ca

1. Review

Congratulations on completing Part 1 of the tutorial. Let's review what we've learned so far:
  1. IDLE (we use the very similar VIDLE) is an integrated development environment for Python. It lets you try out commands one at a time in the Python shell or put several commands together in scripts that can be run with Run → Run Module or with F5. Python programs need to be saved before they can be run in VIDLE. Python programs ("scripts") should be saved with the .py extension.
  2. The examples folder contains many useful scripts to explore and edit. You can navigate around VPython windows with your mouse.
  3. You can use Python interactively, for example to test commands or to do simple calculations. You need to watch out for Python's precedence rules and rules on integer division.
  4. You can create variables that stand in for certain values, and write formulas like

    that are easier to understand. The = sign is an assignment operator that assigns values to the right of = to the variable to the left of the =. We also learned about incrementing variables with assignment statements like a /= 2.
  5. We practiced with a few examples, using print statements and comments to make it clear what we were doing.

Let's practice what we've learned so far, and add a couple of little tricks, with an example from orbital mechanics. According to Kepler's Third Law (see Knight, Second Edition, Chapter 13.6) the orbital period T of a satellite (that is, a very light mass) under the influence of the gravity from a massive body M, such as the Earth or the sun, at a distance r from the centre of M, satisfies

where G is the gravitational constant. One effective way to use computers in physics is to code up simple algebraic formulas like this and test them for various input values.

Activity 0: Now do the following:
  • Write a program that will calculate the orbital period in years of a satellite at a given distance r from a massive body M. Have the program output the period in years and the speed in m/s of the object. To make the program user friendly, ask the user to input the values for r and M. Compare your answers on the period to data found in Table 13.2 of Knight, Second edition. You can use the value π ≈ 3.14159; later we will learn how to access the constant π for mathematical calculations.
  • You will need a couple of new tricks to get this task done. Use the python command input('prompt') to get the user to input values for r and M. The command input('prompt') displays a prompt string and then waits for input from the user. Here is a template for using input('prompt'):
    r = input('Please enter the radius in metres. ')

    This will print Please enter the radius in metres., and then wait for you to input a value and press return. It will then assign the value you input to the variable r in the python script.
  • If you wish to output the value of the angle of separation, it will be useful to print it as a number between 0 degrees and 360 degrees. To do so, you will need to use the mod operator %, which prints the remainder from the division of two numbers. For example 5%2 has the value 1, and 3.2%1.5 has the value 0.2.
  • Another useful trick is to use scientific notation ("e") format for the numbers in your program. For example, the gravitational constant

    would be written as the assignment statement G=6.673e-11 in Python.
  • Give it a try and compare your script to the one we came up with, which you can download here: .The output of a typical session, with parameters appropriate for Earth, can be found here: .

A few comments need to be mentioned about the input() function. This function is actually a composition of two other functions in Python: eval() and raw_input(). The function raw_input() reads all user input as a string, regardless of whether it is entirely numerical or alphabetical or a mixture of both. The function eval() is more complicated, but its effect on strings which are numerical is to essentially convert them to the corresponding number (int or float type). If such a conversion cannot be made, an error will be returned, so input() cannot be used when we are expecting string input. On the other hand, raw_input() can always be used, but we must keep in mind that the input will be read as a string. Strings can be converted to int or float type, when possible, using the functions int(), float() or eval().

Good programming practice: comments and input-output. Notice that our solution script has a lot of comments and the input and output statements are written to be understood by any user. Follow this practice so that anyone, including yourself in several months time, can understand the program. Quality and clarity of your code, comments, and output will factor into our evaluation of your computational work.

We are now ready to begin the next part of the tutorial, which covers the important concepts of functions and modules. Before we do, we wish to remind you that this is not a formal course in Python. So while we will be introducing a lot of concepts here, we do not expect you to learn them thoroughly at this point. Instead, we want to make sure you get a working knowledge and lots of practice. So don't get discouraged if you don't understand all the examples; your understanding will improve as you work more with Python.

2. Introduction to functions and modules; the numpy module

The expression input('Please enter the radius in metres. ') in the previous example is a call to a Python function called "input", which takes an argument in parentheses (), performs an action, and outputs a value. Besides built-in functions like input(), you can get access to functions other people have written, and, as we'll show later, you can define your own functions.

Modules are Python programs that package together several functions, as well as variables, for you to access and use. Using modules allows you to extend Python, reuse code, and take advantage of code created by others. So functions and modules can reduce the amount of coding you have to do.

Before we learn more about functions, we will start with a simple example of using modules. Kepler's formula for the period T above used the constant π; our solution defined this constant as 3.14159. But the constant π is used so often that it has already been defined in one of the standard Python modules. We can find it in an important module named numpy (which is a contraction of "numerical python"). To access π, we can import it from numpy.

Activity 1: Now do the following:
  • If you have an VIDLE session open, please quit and restart. If you do not have a Python shell open, open one using Run → Python Shell.
  • At the prompt type
    >>> pi

    You will probably see the following error message:
    >>> pi
    Traceback (most recent call last):
    File "<pyshell#0>", line 1, in <module>
    NameError: name 'pi' is not defined

    This error happened because the interpreter knew nothing about pi.
  • Now try to load pi as a variable by typing
    >>> from numpy import pi
  • What happens? Nothing, apparently, but at least you didn't get an error message! Now type
    >>> pi

    You should see
    >>> pi

    The import step let the interpreter learn about the constant pi.
  • Now we can use import to access some numpy functions. Let's start with some trigonometric functions. Type the following two lines, one at a time
    >>> from numpy import sin, cos
    >>> print cos(pi), cos(pi/2.0), sin(pi), sin(pi/2.0), sin(3.0*pi/2.0)

    Your output should look like the following.
    -1.0 6.12323399574e-17 1.22464679915e-16 1.0 -1.0

    The interpreter printed out cos(π/2) and sin(π) as very small numbers, quite close to zero. It is clear that the trig functions expect their arguments in radians.

The command
>>> from numpy import sin, cos
specifies that we should use only the two functions sin() and cos() from the numpy package. But the numpy package includes a huge number of commands and to import them all we can type:
>>> from numpy import *
In this line, the symbol * is not the multiplication symbol but a so-called wildcard that stands for all the functions, variables, etc. that are available from numpy.

Activity 2: To practice what we've learned, do the following:
  • We will now work on a program to calculate the distance between two satellites in circular orbit about a massive body M at some time t, given that they are initially aligned with each other and the sun. The expression for this can be found as follows: In time t, each satellite trajectory goes through an angle 2πt/T from its initial position, where T is the period of the orbit. So two satellites become separated by an angular distance

    (see the illustration below).
    By the cosine law, the distance between the planets is given by

    [Don't worry if you do not completely understand the formulas; for now, just take them as given formulas that depend on several variables.]
  • Now write a program that outputs the angular separation and other information. Ask the user to input the value of the mass in kilograms, the radii of the two orbits r1 and r2 in metres, and the time t in days.
  • To make the output more readable, it is a good idea to reduce the angle to a value in the range 0 to 2π radians or 0 to 360 degrees. Suppose the angular separation degrees is represented by the variable delta_theta_degrees. We can use the modulo operator % to do what we want:
    delta_theta_degrees = delta_theta_degrees%360
  • We can now proceed as follows:
    • Use input() to prompt the user for M, r1, and r2.
    • Calculate periods T1 and T2 from Kepler's third law, as we did in the previous example.
    • Calculate the angular distance delta_theta from the first formula.
    • Calculate the distance between the satellites delta_r using the second formula.
    • Output the results.
  • With these steps you should be able to write a fully functional program, try to make it now.
  • Our solution can be found here: . The output from a typical session, with input parameters corresponding to Earth and Mars, can be found here: .

3. Defining your own functions (optional for Year 1 students)

If you are going to evaluate the same expression or perform the same sequence of operations many times in a program, it is tedious and error-prone to keep retyping the same code. It is more efficient to create your own functions, something that Python lets you do easily. Functions make your code better structured, which means easier to write, understand and correct.

Let's start by creating a function to calculate radioactivity using the radioactive decay formula from Part 1 (see Part 1, Activity 7 and Activity 9):

To get the left hand side, you need three pieces of information: the current radioactivity, the elapsed time, and the half life. This means that we need to create a function with three arguments. It's very helpful to imagine how you might use such a function in a program. For example, you could imagine a line in your script that looks like
new_activity = get_new_activity(old_activity, elapsed_time, half_life)
In this line, the new_activity receives the value of the function get_new_activity given the old_activity, the elapsed_time, and the half_life. So, now we know what we want our function to do, and have a basic design for it. How do we tell Python what we want? We create a function using Python's def command. Here's how we implement the function:
#function to calculate radioactivity given half-life formula
#r(t+delta_t) = r(t)*(1/2)**(delta_t/t_h):
#current_activity is r(t), elapsed_time is delta_t, half life is t_h
#elapsed_time and half_life need to be in same time units.
def get_new_activity( current_activity, elapsed_time, half_life):
    answer = current_activity*0.5**(elapsed_time/half_life)
    return answer
There are a few things to notice here.
1. We started the code with a bunch of comments to make it clear what we are doing.
2. The first non-comment line
def get_new_activity( current_activity, elapsed_time, half_life):
consists of the def keyword (command), which tells Python to expect a function definition, the function name get_new_activity, the function arguments (current_activity, elapsed_time, half_life), which are separated by commas and enclosed in parentheses, and the (very important) colon :.

The following lines
    answer = current_activity*0.5**(elapsed_time/half_life)
    return answer
are indented, that is, they are offset from the left margin by a few spaces. The body of the function must always be indented; the number of spaces from the left margin is up to you, but the indentation must be consistent from line to line. These indented lines which define the function are known as a code block. Python uses indented whitespace to indicate code blocks, which we will see over and over again (for more info on blocks see the Python reference); this makes it different from many other programming languages. The VIDLE editor and shell will try to help you with indentation of code blocks code as you create scripts. Try to watch carefully what it does.

Now, what does the function do? The line beginning answer = calculates the radioactivity, and the line return answer outputs the numerical value of answer. Once the return line is reached, the interpreter exits the function.

To use the function, we simply call it like we called the sin() and cos() functions before. For example, the line
print get_new_activity( 4.0, 40.0, 20.)

will print the radioactivity given that the current activity is 4.0 (in arbitrary units), the elapsed time is 40.0 (in arbitrary units), and the half life is 20.0 (in arbitrary units, but the same as the units of the elapsed time). Can you predict the outcome of this call? [Hint: how many half lives have elapsed?]

One other point: because the interpreter carries out commands in the sequence they are written, the function must be defined before the function is used.

Activity 3: Let's try out our new function! Do the following:

Activity 4: More practice
  • Repeat Activities 1 and 2 above, but using defined functions.

You may read more about defining your own functions and modules in the Introduction to Functions and Modules.

4. Summary & Conclusion

One of the topics discussed in this tutorial was the use of the input() function. It allows you to prompt a user for input. This function is not the only function that allows user input but it is one of the most commonly used. It was also mentioned again that commenting your code is very important. Commenting your code allows other people and yourself to understand code that cannot be immediately understood. The last portion of this tutorial covered functions and modules. Functions are a useful tool in organizing and reducing code. If you need to repeat a process multiple times, it is a good idea to make this process into a function. Modules are simply collections of functions and/or constants. It is very important to know how to make you own functions, so try it now.

This concludes Part 2 of the Tutorial.