1. How to Program, Part I
  2. How to Program, Part II
  3. How to Program, Part III
  4. How to Program, Part IV
  5. How to Program, Part V
  6. How to Program, Part VI
  7. exercises
  8. pyMPI tutorial
  9. Calculating PI, Part I
  10. Calculating PI, Part II
  11. Calculating PI, Part III
  12. Dividing Work
  13. More MPI
  14. Poogle - Web Search
  15. Mandelbrot Sets
  16. Mandelbrot, The Code
  17. Mandelbrot, The Images
  18. Mandelbrot In CUDA
  19. Conway's Life, Part I
  20. Life Code Listing
  21. Conway's Life, Part II
  22. MPI Life Code Listing

How to Program, Part IV

Sometimes we may want to take a calculation and re-use it several times in a program. We do this by making a function.

You can think of a function as something that goes to its "In" box for work, does something with what it finds there, and produces something else and puts it in the "Out" box.

Here we show you some examples of really simple functions:

simplef.py
1def timestwo(x):
2    return 2*x
3 
4def plusthree(x):
5    return x+3
6 
7def square(x):
8    return x*x
9 
10print square(plusthree(timestwo(3)))
$ python ./simplef.py
81

Here is a more complex example based on our grocery shopping task:

shop.py
1def ring_up(total,name,price):
2    tax_rate = 6
3    tax = price * tax_rate / 100
4    print name,price,tax
5    return total+price+tax
6 
7total = 0
8total = ring_up(total,"milk",3.89)
9total = ring_up(total,"cookies",1.55)
10total = ring_up(total,"apples",4.99)
$ python ./shop.py
milk 3.89 0.2334
cookies 1.55 0.093
apples 4.99 0.2994

In this case, by defining the function named "ring_up" we've saved ourselves some coding. We can use ring_up() to compute the total of our purchases, along with taxes, as well as an itemized list. Each call to "ring_up" executes the four lines of code present in its definition.

Notice the syntax: the values "total", "name", and "price" are passed to the function named ring_up. These variables are called "arguments." The "return" line causes an exit from the function and returns the computed value.

Variables defined inside a function are not visible outside.

nshop.py
1def ring_up(total,name,price):
2    tax_rate = 6
3    tax = price * tax_rate / 100
4    print name,price,tax
5    return total+price+tax
6 
7total = 0
8total = ring_up(total,"milk",3.89)
9print tax_rate
$ python ./nshop.py
milk 3.89 0.2334
Traceback (most recent call last):
  File "./nshop.py", line 9, in <module>
    print tax_rate
NameError: name 'tax_rate' is not defined

But variables defined outside the function are visible inside.

nshop2.py
1tax_rate = 6
2def ring_up(total,name,price):
3    tax = price * tax_rate / 100
4    print name,price,tax
5    return total+price+tax
6 
7total = 0
8total = ring_up(total,"milk",3.89)
9print tax_rate
$ python ./nshop2.py
milk 3.89 0.2334
6

It is as if the variables inside a function live in their own private world.

Functions can have multiple return points.

multi.py
1def multi(x):
2    if x < 3:
3        return x - 100
4    else:
5        return 2*x
6 
7print multi(2),multi(4)
$ python ./multi.py
-98 8

If a function doesn't have a return statement, it returns "None."

none.py
1def rnone():
2  pass
3 
4print rnone()
$ python ./none.py
None

In our next program, we want to make use of a function we defined in the "shop.py" program above. We can do this using an "import."

ring.py
1import shop
2 
3total = 0
4total = shop.ring_up(total,"fudge",3.25)
5total = shop.ring_up(total,"bag of lemons",1.25)
6total = shop.ring_up(total,"instant tea",1.89)
7print "total =",total
$ python ./ring.py
milk 3.89 0.2334
cookies 1.55 0.093
apples 4.99 0.2994
fudge 3.25 0.195
bag of lemons 1.25 0.075
instant tea 1.89 0.1134
total = 6.7734

Notice what happened. "import shop.py" read the contents of "shop.py" and then made the function "ring_up()" available to us in our ring.py program. However, in order to use it, we have to use the prefix "shop." in front of each call to "ring_up()".

One subtle point here that you should be aware of: integers and floating point numbers are different:

basictypes.py
1print 1/2
2print 1.0/2
3print 1/2.0
4print 1.0/2.0
$ python ./basictypes.py
0
0.5
0.5
0.5

When integers are used, no decimal values are ever calculated. If you want to see decimal points in the result, you have to use them in one of the values involved in the computation. Thus, the tax calculation we did in "shop.py" would fail if we used an integer for the price.

shop_ohno.py
1import shop
2 
3total = 0
4total = shop.ring_up(total,"ding dongs",3)
5print "total =",total # oh notax calculation failed!
$ python ./shop_ohno.py
milk 3.89 0.2334
cookies 1.55 0.093
apples 4.99 0.2994
ding dongs 3 0
total = 3

There are lots of standard functions that you can import.

math1.py
1import math
2 
3print math.sqrt(4)
$ python ./math1.py
2.0

The above program will just print "2" (the function math.sqrt() is the square root function), as you'd expect.

math2.py
1import math
2 
3print math.sin(math.pi/4)
$ python ./math2.py
0.707106781187

Here we see that it is possible to import variables (in this case "math.pi") as well as functions.

rand.py
1import random
2 
3print random.random()
$ python ./rand.py
0.261743293979

This prints a random number between 0.0 and 1.0. Try it!

dice.py
1import random
2 
3for i in range(4):
4  print 'roll =',random.randint(1,6)
$ python ./dice.py
roll = 6
roll = 1
roll = 2
roll = 1

This prints a random number between 1 and 6. Try it!

This next program can be used to fetch the contents of a web page:

url.py
1import urllib
2 
3url = urllib.urlopen("http://scifi.com")
4text = url.readline() 
5print text
$ python ./url.py
<!DOCTYPE HTML>

This probably looks a bit strange to you. Some variables have methods attached to them. In this case, the variable url has a method attached to it called readline. I don't want to dwell on this too deeply, it's just a hint of things to come. We have, however, already seen this kind of thing in lesson 3. Variables of type list have an "append" method inside them.

One last point...

You can return more than one value from a function using something called "tuples." We aren't going to go into too much detail about them here, just to show you this quick example:

tuple.py
1def div(d1,d2):
2    return (d1+d2,d1-d2)
3 
4(a,b)=div(4,2)
5print a,b
$ python ./tuple.py
6 2

The idea is that you can group a set of values together in both the output (line 2), and the input (line 4).

Actually, this also works (for the output) without the parenthesis, but using them might make it easier for you to read the code.

tuple2.py
1def div(d1,d2):
2    return d1+d2,d1-d2
3 
4a,b=div(4,2)
5print a,b
$ python ./tuple2.py
6 2

Here is an example that combines what we know about arrays and functions. In it we will build a new array, one in which the order of elements is reversed relative to the original one.

reverse.py
1def rev(a):
2    b = []
3    n = len(a)
4    for i in range(n):
5        b.append(a[n-i-1])
6    return b
7x = [1,2,3,8,20]
8y = rev(x)
9print x,y
$ python ./reverse.py
[1, 2, 3, 8, 20] [20, 8, 3, 2, 1]

Problems:

  1. What does the function "ad" do?
    what4a.py
    1def ad(a,b):
    2  return a+b
    3 
    4v1 = ad(3,7)
    5v2 = ad(9,2)
    6print v1,v2
    $ python ./what4a.py
    10 11
    
  2. Why doesn't this program print anything?
    what4b.py
    1def pr():
    2  print "Hello"
    3 
    4pr
    $ python ./what4b.py
    
  3. Why does this function print "None" and not 7?
    why40.py
    1def ad(a,b):
    2  s = a+b
    3 
    4v1 = ad(3,4)
    5print v1
    $ python ./why40.py
    None
    
  4. What does the function "sm" do?
    what40.py
    1def sm(a):
    2  s = 0
    3  for v in a:
    4    s += v
    5  return s
    6 
    7print sm([1,3,5])
    8ar = [2,4,6]
    9print sm(ar)
    $ python ./what40.py
    9
    12
    
  5. What does the function "ra" do?
    what41.py
    1import random
    2def ra(n):
    3  a = []
    4  for i in range(n):
    5    a += [random.randint(1,100)]
    6  return a;
    7 
    8print ra(3)
    9ar = ra(5)
    10print ar
    $ python ./what41.py
    [10, 56, 52]
    [17, 20, 73, 73, 26]
    
  6. What does the function "mn" do?
    what42.py
    1import random
    2def mn(a):
    3  r = a[0]
    4  for i in range(1,len(a)):
    5    if a[i] < r:
    6      r = a[i]
    7  return r
    8 
    9ar = []
    10for i in range(3):
    11  ar.append(random.randint(1,100))
    12print mn(ar),ar
    $ python ./what42.py
    35 [35, 36, 68]
    
  7. This program is supposed to print ['h', 'e', 'l', 'l', 'o']. What's wrong with it? How do we fix it?
    wrong43.py
    1li = []
    2for c in "hello":
    3  li = li.append(c)
    4print li
    $ python ./wrong43.py
    Traceback (most recent call last):
      File "./wrong43.py", line 3, in <module>
        li = li.append(c)
    AttributeError: 'NoneType' object has no attribute 'append'
    
  8. Write a function that takes an argument called name and prints out a greeting to that name, i.e. greet("Bob") produces the output: "Hello, Bob".
  9. Write a program that takes two numbers a, and b and returns the smaller number first and the larger number second, i.e minmax(3,4) produces 3,4 and minmax(6,5) produces 5,6.