Saturday, May 26, 2012

Lesson 7 - Custom Functions

Hey!  It's been a while!  Things have been busy, and I haven't gotten around to updating the blog until now.  So without further ado . . .

Custom Functions

Last time, we learned all about loops and some of the things loops can help us do.  Now let's move on to writing your own functions.

A function, if you'll remember, is a bit of code that you pass arguments and get a return.  This way you can do complex operations over and over without having to copy code all over the place.  We've seen functions that turn numbers into strings (and vice versa) and the like, but we haven't written our own yet.  This is where things get interesting.

Create a new folder for lesson 7, open up a new code file, and away we go!

First let's just write a basic function and go from there.  Functions look like this

def combineStrings(string1, string2):
  newString = string1 + string2
  return newString

Don't forget to indent because just like loops and ifs, python needs to know what code you want in this block.  This function we just made takes two strings and returns a new string which is a concatenation of those two strings.  Is it useful?  I don't know, but it serves our purpose, which is to learn about functions.

Now run your program.

Hmmm . . . nothing happend.  Why?  Well, functions have to be called before they do anything.  So down below the function, add this line (without indenting).

print combineStrings("Hello", "there")

Now run your program.

Remember that string concatenation does not automatically put spaces in.  If you wanted your function to do so, you could do something like this:

def combineStrings(string1, string2):
  newString = string1 + " " + string2
  return newString

Now run it.

Now the beauty of having a function to do these things is for a situation in which you had a large number of these calls, and then you decide you want to change the way it works (like, say, adding a space like we did above).  If you didn't have this in a function and simply wrote out the code for each string concatenation, you would have to do a lot of typing to change all of them.  With a function, you change it in one place, and you're done!

Functions don't have to return things, but a lot of the time they do.  Functions that don't have a return value generally affect objects in certain ways.  Remember that when you pass an argument into a function, the variable contains a reference to that object.  Anything you do (short of an assignment statement) affects that object.  For example:

def appendIntToArray(i, arr):

a = []
appendIntToArray(1, a)
appendIntToArray(2, a)
appendIntToArray(3, a)
print a

Again, not a whole lot of practical application, but we're just learning for now.  Run your program now

See?  Even though the variable name a isn't in the function, the object stored in a was affected.  This is one of the cool things about object-oriented programming, but it's also one of the pitfalls.  Speaking of pitfalls, that brings me to the next section.


One of the more difficult (and useful) things to learn in programming is a little thing called scope.  Scope is simply a term for where certain variable names can be used and when they can't.  Scope varies from language to language so we'll concern ourselves with Python's variable scope.

Let me show you what I mean.  First create a new file, and type this

def myFunction():
  myVar = 7
print myVar

Think about what you think will happen, and then run the program.

Was that what you expected?  The scope of the variable myVar was only the function myFunction() and so that's the only place you can use it.  This is incredibly useful, but can be a little tricky.  Just keep in mind that when you do a function, everything you do there exists in its own little world that gets destroyed when the function ends.  The only thing that doesn't are variables that exist in other scopes and whatever return value (or values as we'll see later).

Change your file to this

globalVar = 4

def myFunction():
  myVar = 7
  print myVar
  print globalVar

print globalVar

and run it

See?  Inside myFunction we can access variables outside the function, like globalVar.  Variables that can be accessed from anywhere (with a few exceptions and considerations) are said to have global scope.

Now For Something Useful

Let's write some useful functions with some practical applications.  To start, create a new file.

This function will take an amount of money as an int and give you a string.  If you remember, I mentioned before that using floats for money because of certain considerations.  You certainly could if you wanted (and in certain circumstances, you would), but better than that for most simple situations would be to use an integer and remember that you're using cents and not dollars.  Let's start with our dollar amounts

itemPrices = [550, 399, 1071, 407]

These will be the values we want to add together.  We could have had the user input these values (or gotten them out of a database or something), but where we got them isn't important for this exercise.

First, let's write a function that will take an integer like this and turn it into a string with a decimal point and a dollar sign.

def dollarAmount(amount):
  dollars = amount / 100
  cents   = amount % 100
  return "$" + str(dollars) + "." + str(cents)

That percent sign (%) performs what is called a modulo operation which basically means returning the remainder of the division of two integers.  Integer division by 100 will give us the dollar amount, and the remainder is the cents.

Now you may or may not see the problem with this function, but lets run it and see.  But first we'll need to call that function for each item.  Let's use a for loop

for item in itemPrices:
  print dollarAmount(item)

Now let's run it.

See the $4.7?  That should be $4.07 but we don't have the leading zeros on the cents.  There's actually a very easy way to do this, but I'll cover that in the next lesson.  For now, we'll create a custom function.  Add this function above our dollarAmount function.

def padWithZeros(strNum, numDigits):
  numZeros = numDigits - len(strNum)
  if numZeros <= 0:
    return strNum
    return ("0" * numZeros) + strNum

See that "0" * numZeros in that last return?  Remember that when you use the * operator on a string and an integer that you will get a new string containing that number of repetitions of the original string.  We're using that to give us the right number of leading zeros.

In this function, we take a string version of a number and the number of digits we want it to be.  If the string is already too big, we just return it.  Otherwise we return that string with the right number of leading zeros.

Now let's change our dollarAmount function to use our new function.

def dollarAmount(amount):
  dollars = amount / 100
  cents   = amount % 100
  return "$" + str(dollars) + "." + padWithZeros(str(cents), 2)

Now let's run it and see what happens.

Voila!  It worked.


I think that's enough for now.  I had other things I wanted to mention but I'll save that for next time.  Here's what we learned in this lesson.

  • You can create your own functions by using the def keyword.
  • Functions you create take parameters and return a value.
  • The modulo operation (%) gives you the remainder of an integer division operation

That's it!  Happy programming!

No comments:

Post a Comment