Sunday, May 27, 2012

Variable Scope

I know this was probably confusing, so let's go over it in detail.

Scope


Again, scope is the word we use to describe the ability to access certain variable names in a certain place in our code.  Languages vary on how scope works, but we'll stick with python.

So far, we've learned about two kinds of scope: function scope and global scope.  The two are separate from each other, but there are ways to cross over, but first let's explore what scope means for our programs.

Open a new file and save it where you want (I recommend calling it "scopeTest.py" and putting in a folder called "tests").  Lets start by creating a function and a few variables in various scopes.


globalVar = "This is global"


def myFunction():
  localVar = "This is local"
  print "myFunction - localVar:  " + localVar
  print "myFunction - globalVar: " + globalVar


myFunction()
print
print "global - globalVar: " + globalVar
print "global - localVar:  " + localVar




Can you figure out what will happen?  Let's run it and see if you're right.



Oops.  We couldn't access the variable localVar outside the function.  Ok so let's get rid of the line where we print that out

print "global - localVar:  " + localVar

Now let's make things a little trickier.  Let's change our function to this.


def myFunction():
  localVar = "This is local"
  globalVar = "This is local"
  print "myFunction - localVar:  " + localVar
  print "myFunction - globalVar: " + globalVar



Ok now let's run it and see what happens.



Surprised?  In one place, globalVar was one string, and in the other it was a different one at the same time.  Apparently, when you assign to globalVar inside the function, Python creates a new variable with function scope and hides or shadows the global-scope globalVar.  In order to access the global version of globalVar, we need to add this line underneath the def line.

global globalVar



That should do it.  Now run it.



There we go.  Now when we assign "This is local" to globalVar, we're assigning it to the global version.  You must do this whenever you want to assign to a global variable inside a function.

I hope that clarifies a few things for you about scope.  I know it's just another thing to get your mind around, but trust me: it's not that difficult once it clicks.  All these things make sense together; it just takes a little practice.


Saturday, May 26, 2012

Lesson 8 - Tuples and String Formatting

All right, last time we wrote our own functions, and now we're going to build on that using a few useful constructs of Python.

Tuples


What is a tuple?  A tuple is kind of like a list (see Lesson 4) except that it is immutable (like a string is immutable).  Tuples don't change once you create them; they will always contain the same objects/primitives in the same order.  (The objects themselves can be modified though, and I'll show you what I mean in a little bit).

Let's go back to our trusty old command line interpreter.  If you don't remember how to open it, just open a command prompt/terminal and type python.



Ok, we're ready.  To form a tuple, use parentheses like this

t = (1, 2, 3)
print t



Now you can access each item in the tuple just like a list (remember that both tuples and lists are zero index based, meaning that the "first" element is number 0).

print t[0]
print t[1]
print t[2]


Now, unlike a list, you cannot add, remove, or change the contents of a tuple.  Try this

t[1] = 42



See?  It won't let you.

So you may be wondering what the purpose of tuples are.  Simply put, tuples are just a way to pass around a sequence object (like a list) without worrying about the elements or size changing.


A Tuple of One

Incidentally, if you want to create a tuple with one item in it, you have to put a comma inside the parentheses.

t = (1,)
print t



Otherwise it treats the parentheses like they are part of a math equation, and you will only get the one element.

t = (1)
print t




Tuples in Functions

One of the most practical applications of a tuple is in regard to functions.  In the last lesson, I hinted that a function could return more than one value (which is rather unique to Python) and this is how it does it.

Open a new file and add this function


def valueAndDigits(strNum):
  return int(strNum), len(strNum)




Python treats that return as a tuple.  Now for the cool part.  You see, in Python you can do cool assignment statements like this

a, b = valueAndDigits("147")



Cool, huh?  With this statement, Python assigns the first item of the tuple to a and the second to b.  In order for this to work, you have to be exact—you can't have too many or two few variables or you'll get an error.  Just to see it work, let's print them out

print a
print b



Now run it and see what happens.


Exactly what we expected.  (Granted this isn't the most useful function, but it's only for demonstration purposes).

To see that the return value is indeed a tuple, you can do this


c = valueAndDigits("2048")
print c




And run it



And there you have it.

And now for something completely different . . .


String Formatting

This is perhaps one  of the most useful things in Python (and certain other languages).  Up until now, whenever we wanted to combine strings, we had to concatenate them.  It works, but it's not very pretty and if you have a really big string you want to create, it can get confusing.

To use string formatting, you create a string with markers inside it.  Each marker begins with a % sign and end in a letter which indicates the type of information you want to show.  Strings are %s and integers are %d (I think the d stands for 'decimal' because you could also do %x to show the integer in hexadecimal format).  After that string, you place another % sign and then a tuple with the different variables and values you want to display.  The whole thing looks something like this

"%s is a gr%d language!" % ("Python", 8)

which when run gives you

"Python is a gr8 language!"


Now let's try it.  Open up a new file and type this


name = raw_input("Please type your name: ")
greeting = "Hello, %s.  Welcome to Python!" % (name)
print greeting




Now run it, type a name, and see what happens.



We created a string without having to use any concatenation.

Certain markers have different options that go with it.  For instance, pretty much all markers let you specify a number for the number of spaces you want to fill.   To demonstrate, lets start a new file.  Well first create a function to display a name and number with a certain number of spaces, which will create our table.


def printNameAndNumber(name, num):
  print "%20s %10d" % (name, num)


Now we'll need some names.


printNameAndNumber("Sally", 27828)
printNameAndNumber("Bob", 58732)
printNameAndNumber("Joe", 91237)
printNameAndNumber("Octavian", 11263)
printNameAndNumber("Olivia", 82373)




Now run it.


There you go.

Now the most useful I have saved for last.  For integers (and floats) you can tell the string formatter to put a certain number of leading zeros onto a number.  To do this, simply put a zero before the number in a %d marker.  To demonstrate, let's change our function to this


def printNameAndNumber(name, num):
  print "%20s %010d" % (name, num)


Now run it and see what happens.



See? The 0 before the 10 made all the difference.


Putting It All Together

Now let's revisit the function we created last time—the one that turned an integer into a dollars-and-cents string—and let's use tuples and string formatting this time.

Start a new file, and lets start by creating a function that takes our integer, and returns the dollars and cents.

def dollarsAndCents(amount):
  return amount / 100, amount % 100

There we go.  Now for a function that takes an amount and creates a string, but this time we'll use string formatting.  We'll also use the function we just wrote.

def dollarString(amount):
  dollars, cents = dollarsAndCents(amount)
  return "%d.%02d" % (dollars, cents)

But wait!  We're using the variable amount in two places.  Won't that mess things up?  Actually no.  Remember what we said last time about scope?  Each function variable has its own variable scope, so we can reuse names that can't be accessed by this function.  In this case, amount cannot be accessed by dollarString() because it exists within the function scope of a different function.  If, however, amount had been declared outside the functions in the global scope, then we would have two variables called amount.  We still would be okay inside the function unless we used the global keyword which tells Python that we want to use the variable amount from the global scope, but even that is only because we declared amount as a local variable (in the parameters), and it hides (or shadows) the global variable.   If this is confusing, maybe this will help.  (I'll try to post a more detailed explanation of scope later.)

Ok, now that we have our functions, lets have more fun with tuples.  This time, we'll put them inside a list of items with prices.


items = [
  ("Milk",   359),
  ("Bread",  142),
  ("Cheese", 520),
  ("Coffee", 510),
  ("Bacon",  466)
]

Ok now we'll iterate through them and print them out in columns


for item in items:
  print "%10s $%5s" % (item[0], dollarString(item[1]))



Don't worry if that looks a little complicated.  Just think about it in pieces.  We have the string for the formatting

"%10s $%5s"


that will give us two strings—the first to fill up 10 characters and the second to fill up 5 characters.  (And we'll have the dollar sign lined up on the left to look all pretty.)

Then we have the % that tells Python to do the string formatting.  Then we have our tuple.

(item[0], dollarString(item[1]))

The first item is just pulled right out of the current item in the list, and the second parameter is taking the second item and putting it into our function.  If we didn't have functions, this would look a lot more complicated.

So after all that, you should have something like this.



Now for the moment of truth!  Run that code!



Beautiful!  It worked.  You're well on your way into the world of programming!


Review

Here's what we did today.
  • A tuple is an immutable sequence
  • You create a tuple by placing objects and primitives inside parentheses with commas
  • You cannot change the items in a tuple, but you can modify the actual objects inside (provided they too are not immutable)
  • You can use tuples to return more than one value from a function
  • You can use tuples to assign objects and primitives to multiple variables at the same time
  • You can use string formatting to quickly construct a string from various pieces of data
  • String formatting markers start with a % sign and end with a letter for the time of data you want to place there (eg s for string and d for integer)
  • Numbers between the % and the designated letter determine how many spaces the data will fill and what character will fill the extra space
That's all for now!  Happy programming!








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):
  arr.append(i)


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.


Scope


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
  
myFunction()
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


myFunction()
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
  else:
    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.


Review

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!













Thursday, March 8, 2012

Lesson 6 - Loops

Loops


Last time we learned about input and a little about if statements.  Today, let's talk about loops.  A loop is a block of code that runs a certain number of times (possibly not at all) depending on a condition or some other mechanism.

Before we get started, create a new folder in the python directory we set up in Lesson 3, and call this new folder "Lesson 6"; then open up your text editor and create a new file ("lesson6.py").

[pic]

The while Loop


The while statement begins a loop.  It looks a whole lot like an if statement, but it functions quite differently.  The loop only starts if the beginning condition is met, and the block runs to the end.  Once the loop reaches the end of its block, the condition is tested again.  If the condition is met again, the loop repeats and continues to do so until the condition is False.

How is this useful?  Well, let's think back to the previous lesson and the name entry we did.  Let's do that again, only this time, let's make it so you cannot enter an empty string for a name.  The program will keep asking until you enter a non-empty string.

Let's begin.  Type this in your document:

print "What is your name?"
name = raw_input("Enter your name>")



This will get the name from the user.  Now let's write our while loop to make sure the name is not empty.

while(name==""):
  print "You cannot enter an empty name"
  name = raw_input("Enter your name>")  


Now let's try running what we've got so far.  Open up your console and navigate to your "Lesson 6" folder.  Now run your program

python lesson6.py



Ok we've got our prompt.  Now hit return or Enter a few times.



See?  It keeps running that code over and over, and will run it forever until the condition is False.  That means if we enter something, name will no longer be the empty string, and the loop will terminate.



It worked!  We exited the loop, and the program terminated.

Now let's try something even more useful.  Say you want the user to enter an integer, but you want to be sure that they enter a number and not just letters or symbols (because if you use the int() function on a string that cannot be turned into an integer the program will crash).

Type this into your program

print
print "Now enter an integer."
strNum = raw_input("integer>")



Ok, now how do we test if strNum is an integer?  Turns out there's a string method called isdigit() that will get us pretty close to what we want.  It's not perfect, but it will do for purposes of this exercise.  Type this into your program

while(not strNum.isdigit()):
  print "You must enter a number"
  strNum = raw_input("integer>")



Wait!  What's that not doing there?  If we put not put it before a boolean, we get the opposite of the value (True instead of False, and vice versa).  In this case, we only want to run the loop if strNum is not an integer.

Now after all that, type this

num = int(strNum)



This should work for most integers (if not all).  Now let's get some output going.


print "Ok, " + name 
print "The square of your number is " + str(num * num)




That will the print the name the user entered, plus the square of the number entered.

Another useful thing you can do with loops is do operations for sequences of numbers.  For this example, let's create a new document; save it as a different name (like "lesson6-2.py").

[pic]

Ok, let's start by creating a variable to hold our number.  A common programming standard for situations like this is to use a variable called i.

i = 0

This is going to be our counter.  Let's say we want to add up all the numbers from 1 to 100.  Let's create another variable to hold the sum.

sum = 0

Ok now we need our loop.  The condition for the loop is that i <= 100, so let's start there.  Then we'll add a the value of i to sum.

while(i <= 100):
  sum = sum + i
print sum



Remember that since "print sum" is not indented that it will run after the loop finishes.  If we had indented it, it would print the value of sum each time through the loop.

Now let's run it.



Oops!  What's happening?  We didn't ask for input?  Why isn't anything happening?  That's because we forgot one tiny detail.  See the condition?  Each time through the loop, i is always 0, so we end up looping forever!  We need to change our program a bit.

But first use an interrupt to exit your program.  Hit ctrl+C.



We exited our program.   Ok so now how do we fix the loop?  Just change the loop to be this:


while(i <= 100):
  sum = sum + i
  i = i + 1




Now let's try to run it.



It worked!  Now for a few optimizations.  For instance, when i is 0, we're adding 0 to 0 (in sum).  We really don't need that (not that it matters too much as far as performance goes).  So let's just change

i = 1



That's better.  Now for the assignment with addition.  There are special assignment operators for most mathematical operations that tell Python to, for example, add a number to a variable and store the result back in that variable.  For instance, on the line

sum = sum + i

we can instead say

sum += i



And we can do the same thing for i.

i += 1



There!  Our program is much more succinct.

Now let's move on to another kind of loop.

The for Loop

In Python, the for loop is your friend.  It helps you iterate (repeat a process on) through collections like lists and so forth.  Remember back in Lesson 4 when we first learned about lists and we wrote a program that printed items in a list to the screen one by one using square brackets ([])?  That didn't seem very useful, and it's not.  The better way is to use a for loop.

Open a new file in your text editor and save it (lesson6-3.py).

First we'll create a list of strings.  Let's use names.

nameList = ["Bob", "Sue", "Mary", "Joe"]

Now let's say that we want to print each of those names to the console.  We could do something like this:

print nameList[0]
print nameList[1]
print nameList[2]
print nameList[3]

It works, but it's a lot of duplicate code, and what if we didn't know how long the list was when we were writing the program?  With the for loop, the list can be any size at all.  Here's what the for loop looks like:

for thisName in nameList:

Ok, here's what it means.  We want to create a loop which runs once for each item in nameList.  Each time through the loop, the item from the list we are using will be stored in the variable thisName.  (We know that these will all be strings.)

Now for the useful part.

  print thisName

So the total loop looks like this:


for thisName in nameList:
  print thisName



Now let's run it and see what we get.


It worked!  It went through each item in the list (in order), and we told it to print that item to the console.

There's a way we can do the same thing with a while loop.  First let's create a line.

print "-" * 80

Now let's create a variable that will hold the index of the item we are working on.

i = 0

Now we'll create our loop.

while i < len(nameList):

What does this mean?  Well, let's finish the rest of the loop, and then I'll explain.  (Remember to indent)


  print nameList[i]
  i += 1




All right.  See how in that last line we are adding 1 to i and then reassigning it?  (We could have written it "i = i + 1")  The value in i will always increase by 1 each time through the loop.  The condition of this while loop will remove us from the loop when i is not less than the length of the list.  (Since we're adding 1 each time, this will happen when i equals the length of the list (4).)

So the values being tested for i will be 0, 1, 2, 3, and 4.  When i equals 4, it is no longer less than the length of the list, and the loop doesn't run anymore.

This is what makes zero-based lists so advantageous.  The last item in the list will always be the length of the list minus 1.  Therefore, loops through a zero-based lists always check to see that the index is less than (<) the length.  If this were one-based, we would have to check to see if i was less than or equal to the length (<=) because the last item index and the length of the list would be the same.

Remembering that one thing will help you out a lot in programming.  But see how in this case the for loop is much simpler?  (There will be times when you will want to use a while loop, but we won't get into that now.)

Okay, now let's try it



Ta-da!  Now, if we really wanted to emulate the for loop, we would have done something like this:


i = 0
while i < len(nameList):
  thisName = nameList[i]
  print thisName
  i += 1

As far as our program is concerned, these two loops do the exact same thing—they both go through each item in the list and assign the item to the variable thisName.


Let's Put It All Together

Ok now, let's write a program that incorporates everything we covered in this lesson.  Create a new file and save it (lesson6-4.py).

We are going to make a program that lets the user enter in as many words as he wants.  When that's done, we'll change each word to uppercase and then print them to the screen.

First, we'll create the list to hold the words.  (Okay, they don't necessarily have to be words; they can be any string, but for purposes of this program, we'll call them words.)

wordList = []

Now let's make a variable to hold the user's input.

currentWord = ""

Let's do something to spice things up a bit.  Each time the user enters a word, let's give them a prompt that tells them what number of word they are entering (eg "word 3:").  Let's create a variable to hold that number.

wordNum = 1

Why are we starting at 1?  In user interface design, you generally don't start at 0.  Think of a spreadsheet program (like Microsoft Excel); the numbering starts at 1—not 0.  Thus we will start at one, though we know the actual index will be one less than whatever the prompt says.

Now let's start our loop.

while currentWord != "":

This will kick us out of the loop when the user enters an empty string (in other words, the user just hits return or Enter).  But we have a problem now: the first time through the loop, currentWord is already an empty string.  How can we fix this?  How about we put an input statement before the loop.  Change the line

currentWord = ""

to

currentWord = raw_input("word 1: ")

By doing that, our wordNum will be off by 1 when we start the loop, so let's change it to be

wordNum = 2



There we go.  See how thinking through things helps?  You don't have to get things right the first time; if something doesn't work, or you think of a better way, change it.

Ok now for the body of the loop.  First let's add our word to the list (remember to indent)

  wordList.append(currentWord)

We know for certain that we're not adding an empty string, because we just tested for that as the condition for the loop.  If the user hits return or Enter on the first word, the loop won't run even once.

Now let's create the string for our prompt

  prompt = "word " + str(wordNum) + ": "

I hope that's pretty self-explanatory.  (Remember that the str() function is necessary so we can convert the integer to a string before concatenation.)

Now for the input using the prompt we just made.

  currentWord = raw_input(prompt)

And last but not least, we want to increment (add one to) wordNum.

  wordNum += 1

Without that, our prompt would be "word 2: " each time through the loop.

Now that we've got our word entering loop, let's create a loop to display the uppercase words.  We can do this in one of two ways: we can change them all to uppercase, store them, and then display them; or we can change them to uppercase at the same time as we display them.

The second method is the easiest, since we don't care to have the uppercase words when we're done:

for word in wordList:
  print word.upper()

Remember that upper() (like all string functions) only returns the uppercase string; it doesn't change the original string.

Incidentally, we could have also stored each word as an uppercase string at the time the user entered it by doing this:

  wordList.append(currentWord.upper())

Which way is the best way?  That depends on what you want.  If you don't care to have the original input, convert it when the user enters it.  If you don't care to store the uppercase strings, convert it when you print it.  If you want to keep both, do what we're about to do next.

First, let's make a new list for the uppercaseStrings.

uppercaseWords = []

Now let's go through our list, convert them, and add them to the new list.

for word in wordList:
  uppercaseWords.append(word.upper())

Now to print them.

for word in uppercaseWords:
  print word

There we go.  Now let's run it.



Voila!  It works.

Review
  • Loops are blocks of code that can run more than once.
  • The while loop runs until its condition evaluates to True.
  • Code that is part of the loop is indented.
  • A counter is an integer that is incremented each time through the loop so that you can keep track of how many times the loop has run.
  • The for loop is used to loop through items in a collection (like a list, for example).
Well that's it for now.  See you next time.