WEEK05: functions and lists
 M: who,what,when,where,and why of functions...

LAB 5: still due Saturday...

 - what's the difference between these two loops???

L = [20, -13, 45, 207, 307, 128, 98, 229]

for i in L:
  print i

for i in range(len(L)):
  print i


 - make code more readable
 - make code easier to maintain and debug
 - good for code reuse
 - necessary for large/complex programs

 For example: you are working on a program to draw a heart.
 What would you do if you had to draw many hearts? Wouldn't
 it be nice call a drawHeart function, and give it a size 
 and position, like this:

   drawHeart(position, size, color, window)

 Now you can call that function over and over, giving it
 different positions and sizes!


 Imagine you are planning a party and you ask a friend to help.
 You might give your friend a list of people to invite and some
 money to buy food and stuff. Your friend may give you back some

               you: main()
       your friend: function()
function arguments: list of fiends, amount of money
      return value: list of receipts

def main():
  money = 2500.00
  friends = ["Lisa", "Rich", "Andy", "Frances"]
  recpts = planParty(friends, money)
  print recpts

def planParty(guests, money):
  # here in the function you would use the two variables,
  # guests and money, to plan out the party, keeping a
  # list of all receipts...
  receipts = []
  # at the end of the function, return any receipts
  return receipts


def name(formal parameters):

def functionName(param1, param2, ...):
  do this
  and this
  return this

Terminology related to functions:
  invoking or calling:
    starting the function's execution
    actual values that are inputs into a function
  formal parameters: 
    variables that stand for inputs into a function
  return values: 
    outputs from a function
    the places in a program where a given variable may be referenced 


 - simple functions have no parameters and don't return anything:

def print_greeting():
  print "Hello there, welcome to my program"

 - other functions have parameters and return something to main:

def count_letters(string, letter): 
  count = 0
  for ch in string:
    if ch == letter:
      count = count + 1

  return count 

 in the above count_letters function, whatever string and letter
 are, it will count the number of times the letter is in the string
 and return that number to the caller.

 calling it like this:

   n = count_letters("this is fun", "i")

 would count the number of i's in the string, returning a 2.


 In the above example, "this is fun" and "i" are arguments.
 Inside the count_letters function, the argument "this is fun" is
 assigned to the parameter string (and the argument "i"
 is assigned to the parameter letter).

 All of the variables in count_letters are local in scope, meaning
 they only exist when the function is being executed. Once the function
 is finished, count, ch, letter, and string are gone.

 Functions that return something to the calling program should return
 the same kind of thing every time. For example, count_letters always
 returns an integer.

 Python allows functions to return more that one thing, but that's
 usually not a good idea (and many other languages don't allow this).
 Try to make your functions do just one thing.


 - given a main function like this, write the countVowels() function
   needed to make the program work:

def main():
  """get string, tell how many vowels are in the string"""

  print "Enter a string and I'll tell you how many vowels are in it..."

  ustr = raw_input("string: ")
  numv = countVowels(ustr)

  if numv == 1:
    print "\nThere is %d vowel in that string.\n" % (numv)
    print "\nThere are %d vowels in that string.\n" % (numv)

# --------------------------------------------------------- #

def countVowels(s):
  # write this function

# --------------------------------------------------------- #