Python Programming

the revolution will not be televised

Coursera: Week 5

Learn to Program: The Fundamentals 


Week 5 – while loops, lists, mutability

This week I learned that, of course, I’ve been doing it all wrong. Guido van Rossum has decided that there’s no room for individuality, and Python script must be standardized. To quote from Intermezzo: Coding Style: “Name your classes and functions consistently; the convention is to use CamelCase for classes and lower_case_with_underscores for functions and methods.”  To tell the truth, I was only using CamelCase because  I find underscoring to be unattractive. 


Only a couple of more weeks to go and I’m trying to put it all together. Since the first assignment involved modular arithmetic and 24-hour clocks, I thought I’d take the infamous ‘babysitter’ exercise and re-do it with a 12-hour clock. I guess I am a masochist.

Besides clock arithmetic it has Boolean expressions, if/elif statements, and exception handling. This is the one where I finally had to make friends with the debugger. I’m probably not done with it – it needs more input validation – but since there’s not a lot of code for clock arithmetic online (Python has its own built-in datetime module), I’m posting it anyway .

'''Ex 7. A babysitter charges $2.50 an hour until 9:00 PM when the rate drops
to $1.75 an hour (the children are in bed).
Write a program that accepts a starting time and ending time
in hours and minutes and calculates the total babysitting bill.
You may assume that the starting and ending times are in a single 24 hour period.
Partial hours should be appropriately prorated.'''

A = "Enter the time the sitter arrived in form HH:MM(specify AM or PM): "
B = "Enter the time the sitter left in form HH:MM (specify AM or PM): "
C = "Incorrect input. Please enter the time  the sitter arrived \
in form HH:MM(specify AM or PM): "
D = "Incorrect input. Please enter the time  the sitter left \
in form HH:MM(specify AM or PM): "

def calc_fee(start_time, end_time):
    '''
    str -> float

    Return the sitters fee by converting the given starting time
    and ending time into number of hours (in fractions)
    where noon = 12:00PM and midnight = 12:00AM.

    >>> calc_fee('3:45PM', '8:30PM')
    "The babysitter's fee is: $11.88"
    >>> calc_fee('9:10PM','11:40PM')
    "The babysitter's fee is: $4.38"
    >>> calc_fee('11:20AM','11:10PM')
    "The babysitter's fee is: $27.96"
    >>> calc_fee('9:20AM','11:10AM')
    "The babysitter's fee is: $4.58"
    >>> calc_fee('10:20AM','8:15PM')
    "The babysitter's fee is: $24.79"
    >>> calc_fee('12:40PM','11:50PM')
    "The babysitter's fee is: $25.79"
    >>> calc_fee('10:17AM','10:17PM')
    "The babysitter's fee is: $29.04"
    >>> calc_fee('11:00AM','12:00AM')
    "The babysitter's fee is: $30.25"
    >>> calc_fee('11:00AM','12:00PM')
    "The babysitter's fee is: $2.50"
    >>> calc_fee('10:15AM','11:15PM')
    "The babysitter's fee is: $30.81"
    '''

    #get AM or PM
    start_letter  = start_time[-2]
    end_letter = end_time[-2]

    #get the hours and minutes
    start_hour = eval(start_time.split(':')[0])
    end_hour = eval(end_time.split(':')[0])
    #convert minutes to decimal part of hour
    start_minutes = float(start_time[-4:-2])/60
    end_minutes = float(end_time[-4:-2])/60

    #modulo operation
    time = ((end_hour + end_minutes) - (start_hour + start_minutes))%12
    extra_hours = (end_hour + end_minutes) - 9.0

    # if hours = 12
    if time == 0:
        fee = 2.5*12.0
    # if 0 < hours < 12
    else:
        fee = 2.5*time

    #check if all hours after 9PM
    if start_letter == 'P'  and start_hour >= 9.0 and start_hour !=12:
        fee = fee*0.7
    #check if hours are more than 12 and end after 9PM
    elif end_hour != 12 and start_letter == 'A'\
      and end_letter == 'P' and end_hour > start_hour and end_hour >= 9.0:
        time = time + 12
        fee =  fee*time  - (0.75*(extra_hours))
    #check if hours are more than 12 and end before 9PM
    elif start_letter == 'A'  and end_letter == 'P'\
      and end_hour != 12 and end_hour > start_hour:
        time = time + 12
        fee = 2.5*time
    #check if hours end at midnight
    elif start_letter == 'A'  and end_letter == 'A'\
      and end_hour == 12 and end_hour > start_hour:
        time = time + 12
        fee = fee*time - (0.75*(extra_hours))
    #check for hours after 9PM
    elif  end_hour !=12 and  end_letter == 'P' and end_hour >= 9.0 :
        #subtract 0.75 cents/hour from fee after 9:00 PM
        fee =  fee - (0.75*(extra_hours))
    #check if hours ends at midnight
    elif end_hour == 12 and end_letter == 'A':
        fee =  fee*time - (0.75*(extra_hours))
    else:
        fee = fee

    return "The babysitter's fee is: $%.2f"% fee

def check_input():
    x = raw_input(A)
    y = raw_input(B)
    while True:
        try:
            print calc_fee(x,y)
            break
        except:
            x = raw_input(C)
            y = raw_input(D)

def main():
    check_input()
main()

if __name__ == "__main__":
    import doctest
    doctest.testmod()

Coursera: Week 4 – Is It For You?

Learn to Program: The Fundamentals 


Week 4 – for loops, fancy string manipulation

This is the week I discovered I’m an addict. It was Friday, I had a long to-do list, but made the mistake of checking my e-mail. Oh, the lectures and assignment for the following week are already up. Fast-forward 6 hours and I had viewed the lectures, done the exercise and finished the assignment. I couldn’t stop. To be fair, I did take a detour on Boolean expressions for the assignment.  I still don’t understand them (Zelle covers them in Chapter 8 of his book) but, apparently, they’re good for shortening those ridiculously long if/elif statements I’ve been posting. Anyway, I never did get out of the house.

So, are you the kind of person who can spend hours playing a game, until you get to the final level? Can’t wait for the next edition of “World of Puzzles” to arrive? Are you so bored you’re actually thinking of taking that refresher course in Calculus, but can’t remember the algebra?  Try Python, instead. Programming is guaranteed to eat up as much time as you’ve got. 

Coursera: Week 3 – Beginner Tips

Learn to Program: The Fundamentals 

This is from the syllabus: 

Week 1 – Installing Python, IDLE, mathematical expressions, variables, assignment statement, calling and defining functions, syntax and semantic errors


Week 2 – Strings, input/output, Booleans, function reuse, function design recipe, docstrings


Week 3 – import, namespaces, if statements


As you can see, it’s fairly rigorous. One of the reasons for taking the course is to get feedback from other students so 
I’ve been spending a lot of time on the Discussion Forums and many beginners don’t know what to make of it. So here’s my suggestions to anyone thinking of taking a MOOC to learn Python.

1) Most important – DOWNLOAD it.   Don’t believe them when they tell you that it’s unnecessary. Python 2 or 3 (or both), it doesn’t matter. Check out the Beginner’s Guide for help. It’s week 3 at Coursera and people are dropping out, not because of the programming, but because IDLE is giving them fits. Look at it this way – even if you decide Python’s not for you, knowing how to use an editor is part of being computer literate. 

2) Play with it. Many students are complaining that they can’t understand what they’re being asked, much less give the answers. Before you enroll in a course, consider doing exercises. There are loads of websites for beginners. Some people swear by CodeAcademy (Python 2) or Computer Science Circles (Python 3).  Copy and paste the exercises into the editor instead of just doing them online. Get used to saving scripts, changing them around and running them. After a while, the weirdness wears off and it actually gets to be fun.

3) Coursework takes more time than you think. When the course description says 6-8 hours a week, it means 6-8 hours when you’re awake, when the phone isn’t ringing, when you’re not constantly being  interrupted, etc. If you’re hard up for quality time, consider taking a course that doesn’t have hard deadlines for the quizzes and projects. I haven’t verified this, but I’m told that the courses at  edX and Udacity are more go-at-your-own-pace.

Brush Up Your Quadratic Equations

Python Programming: Chapter 7, Exercise 18.

line through a circle

Line Through a Circle

I’ve been playing with this all afternoon, trying to get the bugs out. Can’t really vouch for the math. It seems to work – at least it did five minutes ago – but when I try to shorten the code (all those mu equations), it weirds out, so I left it as is. If you want to try to “break” the program, as Zelle says, knock yourself out. I’m sure it won’t be that hard.

##18. Take a favorite programming problem from a previous chapter and add
##decisions and/or exception handling as required to make it truly robust
##(will not crash on any inputs) . Trade your program with a friend and have
##a contest to see who can "break" the other's program.
#http://paulbourke.net/geometry/sphereline/

from math import sqrt
from graphics import *

'''
Points P (x,y) on a line defined by two points P1 (x1,y1,) and P2 (x2,y2)
is described by:
P = P1 + u (P2 - P1)
or in each coordinate
x = x1 + u (x2 - x1) = x1 + u*dx
y = y1 + u (y2 - y1) = y1 + u*dy

A circle centered at P3 (0,0) with radius r is described by:
(x )**2 + (y )**2  = r2

Substituting the equation of the line into the circle gives a
quadratic equation of the form
a *u**2 + b* u + c = 0 where:
a = (x2 - x1)**2 + (y2 - y1)**2 = dx**2 + dy**2
b = 2*[x1(x2 - x1)  + y1(y2 - y1)] = 2*(dx*x1 + dy*y1)
c = x1**2 + y1**2  - r**2

The exact behavior is determined by the expression within the square root
b * b - 4 * a * c
If this is less than 0 then the line does not intersect the sphere.
If it equals 0 then the line is a tangent to the sphere intersecting it at
one point, namely at u = -b/2a.
If it is greater then 0 the line intersects the sphere at two points.
'''


win = GraphWin("Draw a Line Through the Circle", 400,400)
win.setCoords(-10.0,-10.0,10.0,10.0)
win.setBackground('LemonChiffon')

def circle(x,y,r,color_fill,color_outline):
    circle = Circle(Point(x,y), r)
    circle.setOutline(color_outline)
    circle.setFill(color_fill)
    circle.draw(win)

def message(msg):
    message = Text(Point(0, -9), msg)
    message.setFill('blue')
    message.draw(win)

def circle_line_intersection(X1,Y1, X2, Y2, r):
    line = Line(Point(X1,Y1), Point(X2,Y2))
    line.setOutline('blue')
    line.setWidth('3')
    line.draw(win)

    dX = (X2 - X1)
    dY = (Y2 - Y1)
    a = dX**2 + dY**2
    b = 2*((dX * X1) + (dY* Y1))
    c = X1**2 + Y1**2 - r**2
    e = X1**2 + Y1**2
    f = X2**2 + Y2**2
    i = b * b - 4.0 * a * c  # discriminant
    u = (-X1*dX - Y1*dY)/a


    # both end points within the circle
    if e < r**2 and f < r**2:
        Txt = 'Line is within Circle at points \ 
(%02.f,%02.f),(%02.f,%02.f)'%(X1,Y1,X2,Y2 )
        message(Txt)

    # disc is < 0 - line does not intersect
    elif   i < 0.0  :
        Txt = 'Line does not intersect Circle.'
        message(Txt)

    # tangent line if disc = 0,
    elif  i == 0:
        mu = -b /(2.0 * a)
        h = (X1 + mu * dX)
        v = (Y1 + mu * dY)
        Txt =  'Line is tangent to the Circle at point(%02.f,%02.f).'%(h,v)
        message(Txt)
        circle(h,v,0.15,'yellow','black')

    # first end point outside of circle and second end point within circle
    elif  e >= r**2 and  f <= r**2:
        mu = (-b - sqrt(i))/(2.0 * a)
        h = (X1 + mu * dX)
        v = (Y1 + mu * dY)
        Txt =  'Line intersects Circle at point (%02.f,%02.f).'%(h,v)
        message(Txt)
        circle(h,v,0.15,'yellow','black')

    # first end point within circle and second end point outside of circle
    elif  e <= r**2 <= f:
        mu = (-b + sqrt(i)) / (2.0 * a)
        h = (X1 + mu * dX)
        v = (Y1 + mu * dY)
        Txt =  'Line intersects Circle at point (%02.f,%02.f).'%(h,v)
        message(Txt)
        circle(h,v,0.15,'yellow','black')


    # secant Line if disc > 0 and neither end point within circle
    elif i > 0.0 and 0.0 < u < 1.0:

        # first intersection
        mu = (-b - sqrt(i)) / (2.0 * a)
        h1 = (X1 + mu * dX)
        v1 = (Y1 + mu * dY)
        circle(h1,v1,0.15,'yellow','black')
        # second intersection
        mu = (-b + sqrt(i)) / (2.0 * a)
        h2 = (X1 + mu * (dX))
        v2 = (Y1 + mu * (dY))
        circle(h2,v2,0.15,'yellow','black')
        Txt = 'Line intersects Circle at points \ 
(%02.f,%02.f),(%02.f,%02.f)'%(h1,v1,h2,v2 )
        message(Txt)

def main():
    instructions = Text(Point(0, 9), 'Click on two points to draw a horizontal line.')
    instructions.setFill('blue')
    instructions.draw(win)
    #center circle
    circle(0,0,5,'orange','green')

    #get the end points of the line
    p = win.getMouse()
    x1 = p.getX()
    y1 = p.getY()
    circle(x1,y1,0.15,'red','red')
    p2 = win.getMouse()
    x2 = p2.getX()
    y2 = p2.getY()
    circle(x2,y2,0.15,'red','red')

    circle_line_intersection(x1,y1,x2,y2, 5)

    instructions.setText ('Click anywhere to quit.')
    win.getMouse()
    win.close()

if __name__ == '__main__':
    main()


Archery Scorer

Python Programming: Chapter 7, Exercise 16.

I used ten-band scoring, with the bull’s-eye worth 11 points. Again, the code could be shorter – but that’s not the purpose of the exercise.

'''16. Archery Scorer. Write a program that draws an archery target
(see Programming Exercise 2 from Chapter 5) and allows the user to click five
times to represent arrows shot at the target. Using five-band scoring, a
bulls-eye (yellow) is worth 9 points and each successive ring is worth 2
fewer points down to 1 for white. The program should output a score for
each click and keep track of a running sum for the entire series.
'''
from graphics import *
import math

win = GraphWin("Archery Target", 500,500)
win.setBackground('gold')
win.setCoords(-250, -250, 250, 250)
cen = Point(0,0)

msg = Text(Point(0,230), 'Click to hit the target.')
msg.setFill('blue')
msg.draw(win)

def score_text(): #put the score numbers on the target
    v = 190
    z = 18

    bullseye = Text(Point(0,0), 'x')
    bullseye.setSize(14)
    bullseye.draw(win)

    for i in range(1,11):
        score_number = Text(Point(0,v), i)
        score_number.setSize(z)
        score_number.setFill('blue')
        score_number.draw(win)
        v = v - 19
        z -= 1

def hit_target(): #draw a circle where the user clicks and add to the count
    count = 0
    for i in range(10):

        p = win.getMouse()
        x = p.getX()
        y = p.getY()
        p = Circle(Point(x,y),4)
        p.setFill('purple')
        p.draw(win)
        d = x**2 + y**2

        string = 'You hit the target. Score is %s.'
        if d > 200**2:
            msg.setText(('You missed the target. Score is %s.' %count))
        elif d <= 10**2:
            count += 11
            msg.setText(('Congrats! You hit the bull's-eye. Score is %s.' %count))
        elif d <= 29**2:
            count += 10
            message = msg.setText((string %count))
        elif d <= 48**2:
            count += 9
            message = msg.setText((string %count))
        elif d <= 67**2:
            count += 8
            message = msg.setText((string %count))
        elif d <= 86**2:
            count += 7
            message = msg.setText((string %count))
        elif d <= 105**2:
            count += 6
            message = msg.setText((string %count))
        elif d <= 124**2:
            count += 5
            message = msg.setText((string %count))
        elif d <= 143**2:
            count += 4
            message = msg.setText((string %count))
        elif d <= 162**2:
            count += 3
            message = msg.setText((string %count))
        elif d <= 181**2:
            count += 2
            message = msg.setText((string %count))
        elif d <= 200**2:
            count += 1
            message = msg.setText((string %count))

    msg.setText('Game over. Score is %s. Click anywhere to quit.' %count)
    win.getMouse()
    win.close()

    return count

def main(): 
    #draw the target
    rad = 200
    color = ['white', 'black', 'cyan3', 'red', 'yellow']
    for i in range(5):
        for j in range(2):
            c = Circle(cen, rad)
            c.setFill(color[i])
            c.setOutline('gray')
            c.setWidth('2')
            c.draw(win)
            rad = (rad - 19)
    #draw the bull's-eye
    center = Circle(cen,10)
    center.setOutline('gray')
    center.setWidth('2')
    center.draw(win)
    score_text()
    hit_target()

if __name__ == '__main__':
    main()

Does a Line Intersect the Circle?

Python Programming: Chapter 7, Exercise 14.

I usually post code for exercises that were either fun to do or required research or gave me a headache. This exercise was none of the above, but I’m posting it because I use it later on, for exercise 18.

##14. Do Programming Exercise 7 from Chapter 5, but add a decision
##to handle the case where the line does not intersect the circle.

from graphics import *
import math

win = GraphWin("Draw a Horizontal Line", 400,400)
win.setCoords(-10.0,-10.0,10.0,10.0)
win.setBackground('LemonChiffon')

def message(msg):
    message = Text(Point(0, -9), msg)
    message.setFill('blue')
    message.draw(win)

def main():
    instructions = Text(Point(0, 9), 'Click on two points to draw a horizontal line.')
    instructions.setFill('blue')
    instructions.draw(win)

    ball = Circle(Point(0,0), 5) #radius is 5 from center 0
    ball.setOutline('green')
    ball.setWidth('2')
    ball.setFill('orange')
    ball.draw(win)

    #draw first point
    p = win.getMouse()
    x1 = p.getX()
    y = p.getY()
    c = Circle(Point(x1,y),0.1)
    c.setFill('blue')
    c.draw(win)
    txt = Text(Point(x1+1,y+.5),'')
    txt.setText('%0.2f, %0.2f' %(x1,y))
    txt.draw(win)

    #draw second point
    p2 = win.getMouse()
    x2 = p2.getX()
    c = Circle(Point(x2,y),0.1)
    c.setFill('blue')
    c.draw(win)
    txt = Text(Point(x2+1,y+.5),'')
    txt.setText('%0.2f, %0.2f' %(x2,y))
    txt.draw(win)

    line = Line(Point(x1,y), Point(x2,y))
    line.setOutline('red')
    line.setWidth('3')
    line.draw(win)

    #is the line above or below the ball?
    if  y >5 or y< -5 :
        Txt = 'Line does not intersect Circle.'
        message(Txt)

    else:
        Txt =  'Line intersects Circle.'
        message(Txt)

        #draw intersect points
        x  = math.sqrt(25 - y**2)
        for i in range(2):
            pt = Circle(Point(x, y),0.15)
            pt.setFill('yellow')
            pt.draw(win)
            x = -x

    instructions.setText ('Click anywhere to quit.')
    win.getMouse()
    win.close()

if __name__ == '__main__':
    main()

Date of Easter from 1900 to 2099

Python Programming: Chapter 7, Exercise 10.
More doctests.

'''10. The formula for Easter in the previous problem works for every year in
the range 1900-2099 except for 1954, 1981, 2049, and 2076. For these
4 years it produces a date that is one week too late. Modify the above
program to work for the entire range 1900-2099.
Check at: http://www.assa.org.au/edm.html
'''
def get_date(year):
    ''' int -> str
    Return the date of Easter given a year between 1900 and 2000
    >>>
    Enter a year between 1900 and 2099: 1922
    In the year  1922 , Easter falls on April 16
    >>>
    Enter a year between 1900 and 2099: 1822
    Illegal date
    >>>
    Enter a year between 1900 and 2099: 1954
    In the year  1954 , Easter falls on April 18
    >>>
    Enter a year between 1900 and 2099: 1981
    In the year  1981 , Easter falls on April 19
    >>>
    Enter a year between 1900 and 2099: 2049
    In the year  2049 , Easter falls on April 18
    >>>
    Enter a year between 1900 and 2099: 2076
    In the year  2076 , Easter falls on April 19
    '''

    if year < 1900 or year > 2099:
        print("Illegal date")
    else:
        a,b,c = year%19,year%4,year%7
        d = (19*a+24)%30
        e = (2*b+4*c+6*d+5)%7
        days_after = d+e
        days = 22+days_after
        if year in [1954, 1981, 2049, 2076]:
               days -= 7
        print"In the year ",year,", Easter falls on",
        if days <= 31:
            print "March " +str(days)
        else:
            print "April " + str(days-31)

def main():
    Year = input("Enter a year between 1900 and 2099: ")
    get_date(Year)
main()

if __name__ == "__main__":
    import doctest
    doctest.testmod()

Date of Easter for the Years 1982-2048

Python Programming: Chapter 7, Exercise 9.

Most of this is from ReexamPracticeQuestionSolutions.pptx (or in my case, .odp). You can download it at: http://www.csee.usf.edu/~rtindell/courses/Python/Solutions/

##from: ReexamPracticeQuestionSolutions.pptx

'''Ex 9.  A formula for computing the date of Easter in the years 1982-2048,
inclusive,is as follows: Let a = year % 19, b = year%4, c = year%7,
d = (19*a + 24)%30, and e = (2*b+4*c+6*d+5)%7.
The date of Easter is (d+e) days after March 22 (which could be in April).
Write a program that inputs a year, verifies that it is in the proper range,
and then prints the date of Easter that year.
Check dates at: http://www.assa.org.au/edm.html'''

def main():

    year =input("Enter a year between 1982 and 2048: ")
    if year < 1982 or year > 2048:
        print("Illegal date")
    else:
        a = year%19
        b = year%4
        c = year%7
        d = (19*a+24)%30
        e = (2*b+4*c+6*d+5)%7
        days_after = d+e
        days = 22+days_after
        print "In year ",year,", Easter falls on",
        if days <= 31:
            print"March " ,str(days)
        else:
            print"April " , str(days-31)

main()

A babysitter charges $2.50 an hour…

Python Programming: Chapter 7, Exercise 7.
I used a 24 hour clock because I’m not a masochist.

'''Ex 7. A babysitter charges $2.50 an hour until 9:00 PM when the rate drops
to $1.75 an hour (the children are in bed).
Write a program that accepts a starting time and ending time
in hours and minutes and calculates the total babysitting bill.
You may assume that the starting and ending times are in a single 24 hour period.
Partial hours should be appropriately prorated.'''

def calcFee(startTime, endTime):
    '''
    str, str -> float

    >>> calcFee('15:45', '20:30')
    'The babysitters fee is: $11.88'
    >>> calcFee('21:10','23:40')
    'The babysitters fee is: $4.38'
    >>> calcFee('11:20','23:10')
    'The babysitters fee is: $27.96'
    '''
    #get the hours and minutes
    startHour = float(startTime.split(':')[0])
    endHour = float(endTime.split(':')[0])
    startMinutes = float(startTime.split(':')[1])
    endMinutes = float(endTime.split(':')[1])
    #turn minutes to decimal part of hour
    time = endHour + endMinutes/60 - (startHour + startMinutes/60)
    fee = 2.5*time

    if endHour < 21:
        fee = fee
    elif 21 <= startHour:
        fee = 1.75*time
    else:
        extraHours = endHour - 21
        #subtract 0.75 cents from fee for time after 9:00 PM
        fee = fee - (0.75*(extraHours  + (endMinutes/60)))

    return "The babysitters fee is: $%.2f"% fee

def main():
    x = raw_input("Using a 24 hour clock, enter the time the sitter arrived: ")
    y = raw_input("Using  a 24 hour clock, enter the time the sitter left: ")

    print calcFee(x,y)

main()

if __name__ == "__main__":
    import doctest
    doctest.testmod()

Quiz Score to Letter Grade

Python Programming: Chapter 7, Exercise 3.
Thought I’d take the opportunity to try out some docstrings. If a test fails, it produces an error message in the interpreter.


'''Ex 2. A certain CS professor gives 5-point quizzes that are graded on the scale
5-A, 4-B, 3-C, 2-D, 1-F, 0-F.
Write a program that accepts a quiz score as an
input and uses a decision structure to calculate the corresponding grade.
'''

def letterGrade(score):
    '''int -> string

    Return a letter grade when given an exam score provided by the user.

    >>> letterGrade(2)
    'D'
    >>> letterGrade(3)
    'C'
    >>> letterGrade(4)
    'B'
    >>> letterGrade(5)
    'A'
    '''

    if score == 5:
        letter = 'A'
    elif score == 4:
        letter = 'B'
    elif score == 3:
        letter = 'C'
    elif score == 2:
        letter = 'D'
    else:
        letter = 'F'
    return letter

def main():
    x = input('Enter a numerical grade: ')
    letter = letterGrade(x)
    print 'Your grade is %s.' % letter
main()

if __name__ == "__main__":
    import doctest
    doctest.testmod()