Thursday, April 5, 2012

Python: When NOT To use Global Variable, Use Return!

Reference: http://stackoverflow.com/q/10036747/1276534
Credit: Ricky, jdi, Maty

Using global variable in your Python function is really easy, but today I read a post that explain why not to use it. And I found it make a lot of sense, I am not used to write without the pass by reference. Take a look at this code below.
def getSalary():
    global a, b, c
    a = input("Please enter the boss's salary")
    b = input("Please enter the director's salary")
    c = input("Please enter the factory worker's salary")

Notice this function, it asks the user for 3 different salary and store them in a, b, c respectively. But it is not a good practice, instead we should use the return function.

def getSalary():
    a = input("Please enter the boss's salary")
    b = input("Please enter the director's salary")
    c = input("Please enter the factory worker's salary")
    return a, b, c

# And to way to use this function is like
a, b, c = getSalary()
This make the code a lot more readable, and useable. Imagine if you make a mistake in the program, if you use global variable, you will have a very hard time tracking where exactly does your value get changed. While doing it the second method, you will know a, b, c is changed on the getSalary line's return. And you can print them as you writing your program to debug it.

And as jdi pointed out, it is always always better to use more meaningful variable name than a,b,c,d, or x,y,z. Imagine you use bossSalary, directorSalary, factoryWorkerSalary, the code is a lot easier to understand. Granted, maybe a little bit long. But maybe you can use workerSalary at least!

And when you have a function that modify your object, such as your own class, a list. Maybe (depending on the situation), you might want to create a new variable and assign it, or you can overwrite it too!
def newSalary(salary):
    return salary + salary * 0.02

# Use it like this
nextYearSalary = newSalary(salary)
# Or overwrite the old one
mySalary = newSalary(salary)

Tuesday, April 3, 2012

Python: How to print the ValueError Error Message

try:
    ...
except ValueError as e:
    print(e)

Python Tkinter: How to set the window size without using canvas

Reference: http://stackoverflow.com/q/9996599/1276534
Credit: George, Bryan Oakley

Here is the code on how to set the window size without using canvas, it is great if you just starting, or do not want to use canvas to do this. You can specify your dimension in your frame, and then use pack_progate(0) flag to tell tkinter to use your size.
import tkinter as tk

root = tk.Tk()
frame = tk.Frame(root, width=400, height=400)
frame.pack_propagate(0) # set the flag to use the size
frame.pack() # remember to pack it or else it will not be pack

textBox = tk.Label(frame, text="(x,y): ")
textBox.pack()

root.mainloop()
Note: If your frame is not big enough to how the items, it will expand to fit your items). And the pack_progate(0) is a flag, it does not replace pack() method, you still have to call it or otherwise it will not appear. Hope this help.

Reference: stackoverflow 1, stackoverflow 2

Monday, April 2, 2012

Python: [] vs. {} vs. ()

Reference: http://stackoverflow.com/q/4407873/1276534
Authors: Zolomon, Greg Hewgill, Andrew Jaffe

It is a good note post to make sure we remember what is [] vs. {} vs. ()

() - tuple

A tuple is a sequence of items that can't be changed (immutable).

[] - list

A list is a sequence of items that can be changed (mutable).

{} - dictionary or set

A dictionary is a list of key-value pairs, with unique keys (mutable). From Python 2.7/3.1, {} can also represent a set of unique values (mutable).

Python: Regular Expression 101 Example Code

Reference: http://stackoverflow.com/q/9980381/1276534
Authors: Rajeev, George

In computer science theory class, we learned about regular expression. But it is unclear what exactly can it do at first, today I would like to introduce data validation as an example that uses the concept of regular expression. Python itself, like other language I assume (heard), has an implementation of regular expression. It comes standard from python too, see: http://docs.python.org/library/re.html

For example, you would like to ask the user for a telephone number, in the format of: 917-222-1234, if it is not in the format of XXX-XXX-XXXX, it will ask the user again until it is store. Let's take a look at the sample code.
import re

while True:
    # Get the user's input into the string
    myString = input('Enter your telephone number: ')
    
    # Matching it with the regular expresssion
    # isGoodTelephone will return True if it matches
    isGoodTelephone = re.match('^[0-9]{3}-[0-9]{3}-[0-9]{4}$', myString)
    
    if (isGoodTelephone):
        print('Great! Got your phone number into the system')
        print('Entry:', myString)
    else:
        print('Not in the correct format. Ex: xxx-xxx-xxxx')
    print()

Output of the csci133rep1.py:
Enter your telephone number: 917-123-1234
Great! Got your phone number into the system
Entry: 917-123-1234

Enter your telephone number: 9171231234
Not in the correct format. Ex: xxx-xxx-xxxx
Actually the basic of the regular expression is not too hard to learn, take a look at the bottom and you will able to figure out how to use it with no problem. Didn't need to put too much comment to make it understandable. Although there are much more ways to use it than just the telephone.
^[0-9]{3}-[0-9]{3}-[0-9]{4}$
^       # mark the start of the telephone string
[0-9]   # any one of the 0123456789
{3}     # match it exactly three times, no less
-       # a hyphen symbol
[0-9]   # any one of the number between 0 and 9
{3}     # exactly three copies
-       # another hyphen symbol
[0-0]   # any one of the number 0-9
{4}     # four times
$       # mark the end of the telephone string

Sunday, April 1, 2012

Python: Calculate Grade Point Average In a 4.0 Scale

This is a simple program that take a list of grade, and then convert it to a 4.0 GPA scale with 1 decimal point, finally calculate the grade point average.
# Take the list of grade as input, assume list is not empty
def convertGrade(myGrades):
    myResult = [] # List that store the new grade
    for grade in myGrades:
        gpa = (grade / 20) -1
        # Depending on how many deciaml you want
        gpa = round(gpa, 1)
        myResult.append(gpa)
    return myResult

# The list of grades, can be more than 5 if you want to
grades = [88.3, 93.6, 50.2, 70.2, 80.5]
convertedGrades = convertGrade(grades)
print(convertedGrades)

total = 0
# If you want the average of them
for grade in convertedGrades:
    total += grade # add each grade into the total
    
average = total / len(convertedGrades)
print('Average GPA is:', average)
Output:
[3.4, 3.7, 1.5, 2.5, 3.0]
Average GPA is: 2.82

Saturday, March 31, 2012

Python: Get the most frequent elements from list when there is more than one

Reference: stackoverflow
Authors: james_kansas, Niklas B.

The question is: When you are given a list that is unsorted, how do you get the most frequent appeared element, in particular, when there is more than one.
from collections import Counter

def myFunction(myDict):
    myMax = 0 # Keep track of the max frequence
    myResult = [] # A list for return
    for key in myDict:
        # Finding out the max frequence
        if myDict[key] >= myMax:
            if myDict[key] == myMax:
                myMax = myDict[key]
                myResult.append(key)
            # Case when it is greater than, we will delete and append
            else:
                myMax = myDict[key]
                del myResult[:]
                myResult.append(key)
    return myResult

foo = ['1', '1', '5', '2', '1', '6', '7', '10', '2', '2']
print('The list:', foo)
myCount = Counter(foo)
print(myCount)

print(myFunction(myCount))
Output
The list: ['1', '1', '5', '2', '1', '6', '7', '10', '2', '2']
Counter({'1': 3, '2': 3, '10': 1, '5': 1, '7': 1, '6': 1})
['1', '2']

More Reading: http://stackoverflow.com/questions/1518522/python-most-common-element-in-a-list

csci133allCombination.py

Reference: http://stackoverflow.com/q/9961077/1276534
Authors: PePe, Li-aung Yip

Overview: Example of this nested while loop is a bad idea, and noting the while loop in python require resetting the loop counter to be 0. And for usage of getting the combination of everything, use either nested for loop with range() function, or itertools, which takes list and return every possible combination from each element in the list you give as argument. And also, xrange() is replaced by range() at 3.0.

In C++, although it might not be recommended, we can write a nested while loop and the following code will work. Because of unknown reason.
a = 0
b = 0
c = 0
while a <= 5:
    while b <=3:
        while c <= 8:
            print(a , b , c)
            c += 1
        b += 1
    a += 1
Output is the following
0 0 0
0 0 1
0 0 2
0 0 3
0 0 4
0 0 5
0 0 6
0 0 7
0 0 8
Answer Because we need to remember to reset the loop's counter, a, b, c respectively on each iteration. But this method is kind of funky.
a = 0
b = 0
c = 0

while a <= 5:
    while b <=3:
        while c <= 8:
            print(a , b , c)
            c += 1
        b += 1
        c = 0 # reset
    a += 1
    b = 0 # reset
    c = 0 # reset
I think most python programmer would prefer using the for loop over the range() function. It is interesting also to note and learn that, xrange() is the range() function, if you are using python 2.x. From 3.0 on, use range instead. :)
for a in range(5+1): # Note xrange(n) produces 0,1,2...(n-1) and does not include n.
    for b in range (3+1):
        for c in range (8+1):
            print(a, b, c)
But then wait... from the Li-aung Yip, there is a better way. Check out this solution which involve using itertools.product()
import itertools
for a, b, c in itertools.product(range(5+1), range(3+1), range(8+1)):
    print a,b,c
For even more reading: Dan Goodger's "Code Like a Pythonista: Idiomatic Python" Thought: I think 2 second way resemble C++ the most to me, I don't know if I want to use while loop even in C++. But it is great to learn another function from the itertools, the itertools.product(). And nice to see the use for for a, b, c. I think it is powerful, but never use it in my code yet, should practice using it.
import itertools

colors = ['red', 'green', 'blue']
vehicles = ['car', 'train', 'ship', 'boat']
numbers = [1, 2, 3, 4, 5]

"""Pints out all the possible combination of number of color vehicles"""
for color, vehicle, number in itertools.product(colors, vehicles, numbers):
    print(number, color, vehicle)

More reference: http://docs.python.org/library/itertools.html

Wednesday, March 28, 2012

csci133c7.py

or known as csci133cleanup.py

In this tutorial we will write a program that clean up the string, it is one of the most classic program. Almost every student will be given a novel text file or input text file and ask them to do something on the data. So the first thing is to "open and load" the text file, and get the English letters into a new string. This tutorial looks long, because I included the full source code of every single program, but in fact it is only minor changes. Read on!
# Version 1 of csci133cleanup.py
# Full implementation of cleanup
wordList = [] # Create a list to store our words
abc = 'abcdefghijklmnopqrstuvwxyz'

with open('novel.text') as book:
    for line in book:
        cleanline = ''
        for character in line.tolower():
            if character in abc:
                cleanline += character
            else:
                # Important! We have append a space!
                cleanline += ' '
        for word in cleanline.split():
            if word not in wordList:
                wordList.append(word)
The first version we are only cleaning up the string text, so there are nothing too special about it. But notice, on line 18, we appended a space to it. Why? Take a moment to think about it, or try to clean 'Doctor--John' on a piece of paper.

Answer: Because we need this mechanism to separate possible words, for example, here is a string Doctor--John. If we did not append a space, we will get 'DoctorJohn' in one word. When we want every single word in the file, we want to separate them instead of keeping them as the same one.
# without space append: Doctor--John, result in DoctorJohn
# with space append: Doctor--John, result in Doctor  John (YES!)
Of course this is not without its problem, for example, we will be left with a lot of 's', so we will want to check if it is already in the list or not. (See line 16), if they are in the list, we might not want to append it again. *Depend on your need, maybe you can add a line number to it. See the next example.
# Version 2 of csci133cleanup.py
# Insert the line numbers into the dictionary
wordList = {} # Create a dictionary to store them
abc = 'abcdefghijklmnopqrstuvwxyz'

with open('novel.text') as book:
    for line in book:
        lineNumber = 1 # Starting at line 1
        cleanline = ''
        for character in line.tolower():
            if character in abc:
                cleanline += character
            else:
                # Important! We have append a space!
                cleanline += ' '
        for word in cleanline.split():
            if word in wordList:
                wordList[word].append(lineNumber)
            else:
                # Store the value as a list that contain 1 item
                wordList[word] = [lineNumber]
        lineNumber += 1
Take a moment to read and compare the code. The very first line is different. We are using a dictionary instead of list. Because when we want to check if the item is in the dictionary already or not, we want to use its build in function, instead of going them one by one. And the other difference is, we are now appending the line number into a list of them. There is an interesting part to it, See line 21.
wordList[word] = [lineNumber]
Notice, we can not use wordList[word] = lineNumber. Because we are creating the first value for the dictionary's key. We instead will create this value as a list that contain one integer. I actually did not aware of this when I was learning python, I keep running into error, because I only used a single interger. And when I try to append to this single integer, it does not work.

The last version we want to search it, we want to look up our dictionary we just created. Take a look at the last couple of lines.
# Version 3 of csci133cleanup.py
# This version include part 1 - 3
wordList = {}
abc = 'abcdefghijklmnopqrstuvwxyz'

with open('novel.text') as book:
    lineNumber = 1
    for line in book:
        cleanline = ''
        for character in line.tolower():
            if character in abc:
                cleanline += character
            else:
                cleanline += ' '
        for word in cleanline.split():
            if word in wordList:
                # do something, such as append line number
                wordList[word].append(lineNumber)
            else:
                wordList[word] = [lineNumber]
        lineNumber += 1

while True:
    word = input('Enter a word here: ' )
    if word in wordList:
         print('Found on lines:, wordList[word])
    else:
         print('Not found.')
wordList = {'apple':[2, 25, 55, 100], 'banana':[5, 10, 36, 90]' ...}
This is the first time we see a while statement in python, the structure of the while loop is simple. while (condition is true), it will execute all the code within it once, and then check if the condition is true, if it is true, do it again, if it is not, it will exist and go to the next statement. See we have 'True' as the condition, that means this loop will run forever, until we kill it with keyboard interrupt.

Keyboard interrupt hot key: Control + C

    Tuesday, March 27, 2012

    csci133ifelif.py

    Reference: http://stackoverflow.com/questions/7052393/python-elif-or-new-if
    Today when I am reading on the python exercises, I came across one of the exercise program it uses elif (in chapter 10). For a second I am not sure what does it mean because it is called differently. But when I read closely to the source file. It looks like it is trying to replaces some of the other if else statements. Finally I look it up online, I found out it is a little bit more than just if else loops.
    def foo(var):
        # Check if var is 5
        if var == 5:
            var = 6
        elif var == 6:
            var = 8
        else:
            var = 10
        return var
    
    def bar(var):
        if var == 5:
            var = 6
        if var == 6:
            var = 8
        if var not in (5, 6):
            var = 10
        return var
    
    print foo(5) # 6
    print bar(5) # 8
    
    You can see the exam of foo(5), if the val is 5. Then the rest of them are treated as (else) loop. The elif is a nested else if loop. It is good (maybe) if you want a cleaner looking program, because you don't have the nested else if loops, the indent level is smaller, and faster compare to a sequence of if, if, if statements, because you are not checking explicitly for every single if statement. Note: always try to put the most common condition on the top, so things can check off the 'list of conditions' faster.

    For example: If you want to check if a string is English word or not, you would want to check if "isalpha()" or not, and then you start to clean up the letters. So that way, your loop will exist as soon as it knows it contain non-letter characters.