10.4 Short-Circuiting: For in If
10.4 Short-Circuiting: For in If
10.4 Short-Circuiting: For in If
SHORT-CIRCUITING 91
10.4 Short-circuiting
Say we are writing a program that searches a list of words for those whose fifth character is 'z'.
We might try the following:
for w in words:
if w[4]== 'z ':
print(w)
But with this, we will occasionally get a string index out of range error. The problem is that
some words in the list might be less than five characters long. The following if statement, however,
will work:
if len(w)>=5 and w[4]== 'z ':
It might seem like we would still get an error because we are still checking w[4], but there is no
error. The key to why this works is short-circuiting. Python starts by checking the first part of the
condition, len(w)>=5. If that condition turns out to be false, then the whole and condition is
guaranteed to be false, and so there is no point in even looking at the second condition. So Python
doesn’t bother with the second condition. You can rely on this behavior.
Short-circuiting also happens with or conditions. In this case, Python checks the first part of the or
and if it is true, then the whole or is guaranteed to be true, and so Python will not bother checking
the second part of the or.
10.5 Continuation
Sometimes you’ll write a long line of code that would be more readable if it were split across two
lines. To do this, use a backslash \ character at the end of the line to indicate that the statement
continues onto the next line. Here is an example:
if 'a ' in string or 'b ' in string or 'c ' in string \
or 'd ' in string or 'e ' in string:
Make sure there are no extra spaces after the backslash or you will get an error message.
If you are entering a list, dictionary, or the arguments of a function, the backslash can be left out:
L = [ 'Joe ', 'Bob ', 'Sue ', 'Jimmy ', 'Todd ', 'Frank ',
'Mike ', 'John ', 'Amy ', 'Edgar ', 'Sam ']
10.6 pass
The pass statement does nothing. Believe it or not, such a thing does have a few uses that we will
see later.
92 CHAPTER 10. MISCELLANEOUS TOPICS II
Suppose we are writing a program that calculates a 25% tip on a bill of $23.60. When we multiply,
we get 5.9, but we would like to display the result as $5.90, not $5.9. Here is how to do it:
a = 23.60 * .25
print( 'The tip is {:.2f} '.format(a))
The way the format method works is we put a pair of curly braces {} anywhere that we want a
formatted value. The arguments to the format function are the values we want formatted, with the
first argument matching up with the first set of braces, the second argument with the second set of
braces, etc. Inside each set of curly braces you can specify a formatting code to determine how the
corresponding argument will be formatted.
Formatting integers To format integers, the formatting code is {:d}. Putting a number in front
of the d allows us to right-justify integers. Here is an example:
print( '{:3d} '.format(2))
print( '{:3d} '.format(25))
print( '{:3d} '.format(138))
2
25
138
The number 3 in these examples says that the value is allotted three spots. The value is placed as
far right in those three spots as possible and the rest of the slots will be filled by spaces. This sort
of thing is useful for nicely formatting tables.
To center integers instead of right-justifying, use the ^ character, and to left-justify, use the < char-
acter.
print( '{:^5d} '.format(2))
print( '{:^5d} '.format(222))
print( '{:^5d} '.format(13834))
2
122
13834
Each of these allots five spaces for the integer and centers it within those five spaces.
Putting a comma into the formatting code will format the integer with commas. The example below
prints 1,000,000:
print( '{:,d} '.format(1000000))
10.8. NESTED LOOPS 93
Formatting floats To format a floating point number, the formatting code is {:f}. To only display
the number to two decimal places, use {:.2f}. The 2 can be changed to change the number of
decimal places.
You can right-justify floats. For example, {:8.2f} will allot eight spots for its value—one of those
is for the decimal point and two are for the part of the value after the decimal point. If the value
is 6.42, then only four spots are needed and the remaining spots are filled by spaces, causing the
value to be right-justified.
Formatting strings To format strings, the formatting code is {:s}. Here is an example that centers
some text:
print( '{:^10s} '.format( 'Hi '))
print( '{:^10s} '.format( 'there! '))
Hi
there!
Hi
there!
There is a whole lot more that can be done with formatting. See the Python documentation [1].
You can put loops inside of other loops. A loop inside of another loop is said to be nested, and you
can, more or less, nest loops as deeply as you want.
for i in range(1,11):
for j in range(1,11):
print( '{:3d} '.format(i*j), end= ' ')
print()
A multiplication table is a two-dimensional object. To work with it, we use two for loops, one for
the horizontal direction and one for the vertical direction. The print statement right justifies the
products to make them look nice. The end='' allows us to print several things on each row. When
we are done printing a row, we use print() to advance things to the next line.
94 CHAPTER 10. MISCELLANEOUS TOPICS II
Example 2 A common math problem is to find the solutions to a system of equations. Sometimes
you want to find only the integer solutions, and this can be a little tricky mathematically. However,
we can write a program that does a brute force search for solutions. Here we find all the integer
solutions (x, y) to the system 2x + 3 y = 4, x − y = 7, where x and y are both between -50 and 50.
for x in range(-50,51):
for y in range(-50,51):
if 2*x+3*y==4 and x-y==7:
print(x,y)
Example 3 A Pythagorean triple is a triple of numbers (x, y, z) such that x 2 + y 2 = z 2 . For instance
(3, 4, 5) is a Pythagorean triple because 32 + 42 = 52 . Pythagorean triples correspond to triangles
whose sides are all whole numbers (like a 3-4-5-triangle). Here is a program that finds all the
Pythagorean triples (x, y, z) where x , y , and z are positive and less than 100.
for x in range(1,100):
for y in range(1,100):
for z in range(1,100):
if x**2+y**2==z**2:
print(x,y,z)
If you run the program, you’ll notice that there are redundant solutions. For instance, (3, 4, 5) and
(4, 3, 5) are both listed. To get rid of these redundancies, change the second loop so that it runs from
x to 100. This way, when x is 4, for instance, the first value for y that will be searched is 4, rather
than 1, and so we won’t get the redundant (4, 3, 5). Also change the third loop so that it runs from
y to 100.
As you look through the solutions, you might also notice that there are many solutions that are
multiples of others, like (6, 8, 10), and (9, 12, 15) are multiples of (3, 4, 5). The following program
finds only primitive Pythagorean triples, those that aren’t multiples of another triple. The way it
does this is every time a new triple is found, it checks to make sure that x, y, and z are not all
divisible by the same number.
for x in range(1,100):
for y in range(x,100):
for z in range(y,100):
if x**2+y**2==z**2:
for i in range(2,x):
if x%i==0 and y%i==0 and z%i==0:
break
else:
print((x,y,z), end= ' ')
Example 4 In Section 15.7, we will write a game to play tic-tac-toe. The board is a 3 × 3 grid, and
we will use nested for loops to create it.
10.9. EXERCISES 95
Example 5 Your computer screen is grid of pixels. To draw images to the screen, we often use
nested for loops—one loop for the horizontal direction, and one for the vertical direction. See
Sections 18.2 and 22.6 for examples.
Example 6 List comprehensions can contain nested for loops. The example below returns a list of
all the vowels in a list of words.
[char for item in L for char in item if char in 'aeiou ']
10.9 Exercises
1. Write a program that uses list and range to create the list [3,6, 9, . . . , 99].
2. Write a program that asks the user for a weight in kilograms. The program should convert
the weight to kilograms, formatting the result to one decimal place.
3. Write a program that asks the user to enter a word. Rearrange all the letters of the word
in alphabetical order and print out the resulting word. For example, abracadabra should
become aaaaabbcdrr.
4. Write a program that takes a list of ten prices and ten products, applies an 11% discount to
each of the prices displays the output like below, right-justified and nicely formatted.
Apples $ 2.45
Oranges $ 18.02
...
Pears $120.03
5. Use the following two lists and the format method to create a list of card names in the format
card value of suit name (for example, 'Two of Clubs').
suits = [ 'Hearts ', 'Diamonds ', 'Clubs ', 'Spades ']
values = [ 'One ', 'Two ', 'Three ', 'Four ', 'Five ', 'Six ', 'Seven ',
'Eight ', 'Nine ', 'Ten ', 'Jack ', 'Queen ', 'King ', 'Ace ']
6. Write a program that uses a boolean flag variable in determining whether two lists have any
items in common.
7. Write a program that creates the list [1,11,111,1111,...,111...1], where the entries
have an ever increasing number of ones, with the last entry having 100 ones.
8. Write a program to find all numbers between 1 and 1000 that are divisible by 7 and end in a
6.
9. Write a program to determine how many of the numbers between 1 and 10000 contain the
digit 3.
96 CHAPTER 10. MISCELLANEOUS TOPICS II
10. Adding certain numbers to their reversals sometimes produces a palindromic number. For
instance, 241 + 142 = 383. Sometimes, we have to repeat the process. For instance, 84 + 48 =
132 and 132 + 231 = 363. Write a program that finds both two-digit numbers for which this
process must be repeated more than 20 times to obtain a palindromic number.
11. Write a program that finds all pairs of six-digit palindromic numbers that are less than 20
apart. One such pair is 199991 and 200002.
12. The number 1961 reads the same upside-down as right-side up. Print out all the numbers
between 1 and 100000 that read the same upside-down as right-side up.
13. The number 99 has the property that if we multiply its digits together and then add the sum
of its digits to that, we get back to 99. That is, (9 × 9) + (9 + 9) = 99. Write a program to find
all of the numbers less than 10000 with this property. (There are only nine of them.)
14. Write a program to find the smallest positive integer that satisfies the following property: If
you take the leftmost digit and move it all the way to the right, the number thus obtained is
exactly 3.5 times larger than the original number. For instance, if we start with 2958 and move
the 2 all the way to the right, we get 9582, which is roughly 3.2 times the original number.
15. Write a program to determine how many zeroes 1000! ends with.
16. Write a program that converts a decimal height in feet into feet and inches. For instance, an
input of 4.75 feet should become 4 feet, 9 inches.
17. Write a program that repeatedly asks the user to enter a height in the format feet’inches" (like
5'11" or 6'3". The user indicates they are done entering heights by entering done. The
program should return a count of how many 4-footers, 5-footers, 6-footers, and 7-footers
were entered.
18. Write a program that repeatedly asks the user to enter a football score in the format winning
score-losing score (like 27-13 or 21-3). The user indicates they are done entering scores by
entering done. The program should then output the highest score and the lowest score out of
all the scores entered.
19. Write a program that repeatedly asks the user to enter a birthday in the format month/day
(like 12/25 or 2/14). The user indicates they are done entering birthdays by entering done.
The program should return a count of how many of those birthdays are in February and how
many are on the 25th of some month (any month).
20. Write a program that asks the user to enter a date in the format mm/dd/yy and converts it
to a more verbose format. For example, 02/04/77 should get converted into February 4,
1977.
21. Write a program that asks the user to enter a fraction in the form of a string like '1/2' or
'8/24'. The program should reduce the fraction to lowest terms and print out the result.
22. Write a program to find all four solutions to the following problem: If a starfruit is worth $5,
a mango is worth $3, and three oranges together cost $1, how many starfruits, mangoes, and
oranges, totaling 100, can be bought for $100?
10.9. EXERCISES 97
23. The currency of a strange country has coins worth 7 cents and 11 cents. Write a program to
determine the largest purchase price that cannot be paid using these two coins.
24. Here is an old puzzle you can solve using brute force by using a computer program to check
all the possibilities: In the calculation 43 + 57 = 207, every digit is precisely one away from
its true value. What is the correct calculation?
25. Write a program that finds all integer solutions to Pell’s equation x 2 − 2 y 2 = 1, where x and
y are between 1 and 100.
26. Write a program that asks the user for a number and prints out all the ways to write the
number as difference of two perfect squares, x 2 − y 2 , where x and y are both between 1 and
1000. Writing a number as a difference of two squares leads to clever techniques for factoring
large numbers.
27. Write a program that simulates all possible rolls of four dice and for each simulated roll, finds
the sums of pairs of dice. For instance, if the roll is 5 1 2 4, the sums are 6, 8, 9, 3 ,5, and 6.
For each of the possible sums from 2 to 12, find the total number of simulated rolls in which
the sum appears and what percentage of the simulated rolls had those sums appear. Output
the totals and percentages, nicely formatted, with the percentages formatted to one decimal
place. To check your work, you should find that the sum 2 comes up in 171 rolls, which is
13.2% of the rolls.
28. In a magic square, each row, each column, and both diagonals add up to the same number.
A partially filled magic square is shown below. Write a program to check through all the
possibilities to fill in the magic square.
5 _ _
_ 6 2
3 8 _
29. The following is useful as part of a program to play Minesweeper. Suppose you have a 5 × 5
list that consists of zeros and M’s. Write a program that creates a new 5 × 5 list that has M’s in
the same place, but the zeroes are replaced by counts of how many M’s are in adjacent cells
(adjacent either horizontally, vertically, or diagonally). An example is shown below. [Hint:
short-circuiting may be helpful for avoiding index-out-of-range errors.]
0 M 0 M 0 1 M 3 M 1
0 0 M 0 0 1 2 M 2 1
0 0 0 0 0 2 3 2 1 0
M M 0 0 0 M M 2 1 1
0 0 0 M 0 2 2 2 M 1
30. Pascal’s triangle is shown below. On the outside are 1’s and each other number is the sum of
the two numbers directly above it. Write a program to generate Pascal’s triangle. Allow the
user to specify the number of rows. Be sure that it is nicely formatted, like below.
1
1 1
98 CHAPTER 10. MISCELLANEOUS TOPICS II
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
31. Given two dates entered as strings in the form mm/dd/yyyy where the years are between
1901 and 2099, determine how many days apart they are. Here is a bit of information that
may be useful: Leap years between 1901 and 2099 occur exactly every four years, starting at
1904. February has 28 days, 29 during a leap year. November, April, June, and September
each have 30 days. The other months have 31 days.
32. Monte Carlo simulations can be used to estimate all sorts of things, including probabilities of
coin flip and dice events. As an example, to estimate the probability of rolling a pair of sixes
with two dice, we could use random integers to simulate the dice and run the simulation
thousands of times, counting what percentage of the time a pair of sixes comes up.
(a) Estimate the probability of rolling a Yahtzee in a single roll of five dice. That is estimate
the probability that when rolling five dice they all come out to be the same number.
(b) Estimate the probability of rolling a large straight in a single roll of five dice. A large
straight is a roll where the dice come out 1-2-3-4-5 or 2-3-4-5-6 in any order.
(c) Estimate the average longest run of heads or tails when flipping a coin 200 times.
(d) Estimate the average number of coin flips it takes before five heads in a row come up.
(e) Estimate the average number of coin flips it takes before the string s comes up, where s
is a string of heads and tails, like HHTTH.
Chapter 11
Dictionaries
A dictionary is a more general version of a list. Here is a list that contains the number of days in
the months of the year:
days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
If we want the number of days in January, use days[0]. December is days[11] or days[-1].
To get the number of days in January, we use days['January']. One benefit of using dictionaries
here is the code is more readable, and we don’t have to figure out which index in the list a given
month is at. Dictionaries have a number of other uses, as well.
11.1 Basics
To declare a dictionary we enclose it in curly braces, {}. Each entry consists of a pair separated
by a colon. The first part of the pair is called the key and the second is the value. The key acts like
an index. So in the first pair, 'A':100, the key is 'A', the value is 100, and d['A'] gives 100.
Keys are often strings, but they can be integers, floats, and many other things as well. You can mix
different types of keys in the same dictionary and different types of values, too.
99
100 CHAPTER 11. DICTIONARIES
• To add a new entry to the dictionary, we can just assign it, like below:
d[ 'C ']=500
Note that this sort of thing does not work with lists. Doing L[2]=500 on a list with two
elements would produce an index out of range error. But it does work with dictionaries.
Empty dictionary The empty dictionary is {}, which is the dictionary equivalent of [] for lists or
'' for strings.
Important note The order of items in a dictionary will not necessarily be the order in which put
them into the dictionary. Internally, Python rearranges things in a dictionary in order to optimize
performance.
Example 2 The following dictionary is useful in a program that works with Roman numerals.
numerals = { 'I ':1, 'V ':5, 'X ':10, 'L ':50, 'C ':100, 'D ':500, 'M ':1000}
Example 3 In the game Scrabble, each letter has a point value associated with it. We can use the
following dictionary for the letter values:
points = { 'A ':1, 'B ':3, 'C ':3, 'D ':2, 'E ':1, 'F ':4, 'G ':2,
'H ':4, 'I ':1, 'J ':8, 'K ':5, 'L ':1, 'M ':3, 'N ':1,
'O ':1, 'P ':3, 'Q ':10, 'R ':1, 'S ':1, 'T ':1, 'U ':1,
'V ':4, 'W ':4, 'X ':8, 'Y ':4, 'Z ':10}
11.3. WORKING WITH DICTIONARIES 101
The deck is actually a list of 52 dictionaries. The shuffle method can be used to shuffle the deck:
shuffle(deck)
The first card in the deck is deck[0]. To get the value and the suit of the card, we would use the
following:
deck[0][ 'value ']
deck[0][ 'suit ']
Copying dictionaries Just like for lists, making copies of dictionaries is a little tricky for reasons
we will cover later. To copy a dictionary, use its copy method. Here is an example:
d2 = d.copy()
in The in operator is used to tell if something is a key in the dictionary. For instance, say we
have the following dictionary:
d = { 'A ':100, 'B ':200}
Referring to a key that is not in the dictionary will produce an error. For instance, print(d['C'])
will fail. To prevent this error, we can use the in operator to check first if a key is in the dictionary
before trying to use the key. Here is an example:
letter = input( 'Enter a letter: ')
if letter in d:
print( 'The value is ', d[letter])
else:
print( 'Not in dictionary ')
You can also use not in to see if a key is not in the dictionary.
102 CHAPTER 11. DICTIONARIES
Looping Looping through dictionaries is similar to looping through lists. Here is an example that
prints the keys in a dictionary:
for key in d:
print(key)
Lists of keys and values The following table illustrates the ways to get lists of keys and values
from a dictionary. It uses the dictionary d={'A':1,'B':3}.
Here is a use of d.items to find all the keys in a dictionary d that correspond to a value of 100:
d = { 'A ':100, 'B ':200, 'C ':100}
L = [x[0] for x in d.items() if x[1]==100]
dict The dict function is another way to create a dictionary. One use for it is kind of like the
opposite of the items method:
d = dict([( 'A ',100),( 'B ',300)])
This creates the dictionary {'A':100,'B':300}. This way of building a dictionary is useful if
your program needs to construct a dictionary while it is running.
We can use dictionaries to count how frequently certain words appear in a text.
11.4. COUNTING WORDS 103
In Section 12.1, we will learn how to read from a text file. For now, here’s a line of code that reads
the entire contents of a file containing the text of Shakespeare’s Romeo and Juliet and stores the
contents in a string called text:
text = open( 'romeoandjuliet.txt ').read()
To get at the individual words, we will use the split method to turn the string into a list of its
individual words. Also, because some words may be capitalized, we will convert the whole string
to lowercase. We also have to remove punctuation.
from string import punctuation
text = text.lower()
for p in punctuation:
text = text.replace(p, '')
words = text.split()
Next comes the dictionary code that does the counting. The dictionary keys will be the words from
the text and the values will be counts of how many time each word appears. We start with an
empty dictionary. Then for every word in the list of words, if we have seen the word before, we
add one to its count, and otherwise we set the count for that word equal to 1. Here is the code:
d = {}
for w in words:
if w in d:
d[w] = d[w] + 1
else:
d[w] = 1
Once we have created the dictionary, we can use the following code to print the items in alphabeti-
cal order:
items = list(d.items())
items.sort()
for i in items:
print(i)
The way this works is a little tricky. Remember that d.items() returns a list of pairs (called
tuples), which are a lot like lists. When we sort a list of tuples, the sorting is done by the first entry,
which in this case is the word. So the sorting is done alphabetically.
If we instead want to order things by frequency, we can flip the order of the tuples and then sort:
items = list(d.items())
items = [(i[1], i[0]) for i in items]
items.sort()
for i in items:
print(i)
# read from file, remove caps and punctuation, and split into words
text = open( 'romeoandjuliet.txt ').read()
104 CHAPTER 11. DICTIONARIES
text = text.lower()
for p in punctuation:
text = text.replace(p, '')
words = text.split()
11.5 Exercises
1. Write a program that repeatedly asks the user to enter product names and prices. Store all
of these in a dictionary whose keys are the product names and whose values are the prices.
When the user is done entering products and prices, allow them to repeatedly enter a product
name and print the corresponding price or a message if the product is not in the dictionary.
2. Using the dictionary created in the previous problem, allow the user to enter a dollar amount
and print out all the products whose price is less than that amount.
3. For this problem, use the dictionary from the beginning of this chapter whose keys are month
names and whose values are the number of days in the corresponding months.
(a) Ask the user to enter a month name and use the dictionary to tell them how many days
are in the month.
(b) Print out all of the keys in alphabetical order.
(c) Print out all of the months with 31 days.
(d) Print out the (key-value) pairs sorted by the number of days in each month
11.5. EXERCISES 105
(e) Modify the program from part (a) and the dictionary so that the user does not have to
know how to spell the month name exactly. That is, all they have to do is spell the first
three letters of the month name correctly.
4. Write a program that uses a dictionary that contains ten user names and passwords. The
program should ask the user to enter their username and password. If the username is not in
the dictionary, the program should indicate that the person is not a valid user of the system. If
the username is in the dictionary, but the user does not enter the right password, the program
should say that the password is invalid. If the password is correct, then the program should
tell the user that they are now logged in to the system.
5. Repeatedly ask the user to enter a team name and the how many games the team won and
how many they lost. Store this information in a dictionary where the keys are the team names
and the values are lists of the form [wins, losses].
(a) Using the dictionary created above, allow the user to enter a team name and print out
the team’s winning percentage.
(b) Using the dictionary, create a list whose entries are the number of wins of each team.
(c) Using the dictionary, create a list of all those teams that have winning records.
6. Repeatedly ask the user to enter game scores in a format like team1 score1 - team2 score2. Store
this information in a dictionary where the keys are the team names and the values are lists of
the form [wins, losses].
7. Create a 5 × 5 list of numbers. Then write a program that creates a dictionary whose keys are
the numbers and whose values are the how many times the number occurs. Then print the
three most common numbers.
8. Using the card dictionary from earlier in this chapter, create a simple card game that deals
two players three cards each. The player with the highest card wins. If there is a tie, then
compare the second highest card and, if necessary, the third highest. If all three cards have
the same value, then the game is a draw.
9. Using the card dictionary from earlier in the chapter, deal out three cards. Determine the
following:
(a) If the three cards form a flush (all of the same suit)
(b) If there is a three-of-a-kind (all of the same value)
(c) If there is a pair, but not three-of-a-kind
(d) If the three cards form a straight (all in a row, like (2, 3, 4) or (10, Jack, Queen))
10. Using the card dictionary from earlier in the chapter run a Monte Carlo simulation to estimate
the probability of being dealt a flush in a five card hand. See Exercise 32 of Chapter 10 for
more about Monte Carlo simulations.
11. In Section 6.10 we met the substitution cipher. This cipher replaces every letter with a different
letter. For instance every a might be replaced with an e, every b might be replaced with an
106 CHAPTER 11. DICTIONARIES
a, etc. Write a program that asks the user to enter two strings. Then determine if the second
string could be an encoded version of the first one with a substitution cipher. For instance,
CXYZ is not an encoded version of BOOK because O got mapped to two separate letters.
Also, CXXK is not an encoded version of BOOK, because K got mapped to itself. On the other
hand, CXXZ would be an encoding of BOOK. This problem can be done with or without a
dictionary.
C C# D D# E F F# G G# A A# B
The notes for the C major chord are C, E, G. A mathematical way to get this is that E is 4 steps
past C and G is 7 steps past C. This works for any base. For example, the notes for D major
are D, F#, A. We can represent the major chord steps as a list with two elements: [4,7]. The
corresponding lists for some other chord types are shown below:
Minor [3,7] Dominant seventh [4,7,10]
Augmented fifth [4,8] Minor seventh [3,7,10]
Minor fifth [4,6] Major seventh [4,7,11]
Major sixth [4,7,9] Diminished seventh [3,6,10]
Minor sixth [3,7,9]
Write a program that asks the user for the key and the chord type and prints out the notes of
the chord. Use a dictionary whose keys are the (musical) keys and whose values are the lists
of steps.
14. Dictionaries provide a convenient way to store structured data. Here is an example dictio-
nary:
d=[{ 'name ': 'Todd ', 'phone ': '555-1414 ', 'email ': '[email protected] '},
{ 'name ': 'Helga ', 'phone ': '555-1618 ', 'email ': '[email protected] '},
{ 'name ': 'Princess ', 'phone ': '555-3141 ', 'email ': ''},
{ 'name ': 'LJ ', 'phone ': '555-2718 ', 'email ': '[email protected] '}]
Write a program that reads through any dictionary like this and prints the following:
15. The following problem is from Chapter 6. Try it again, this time using a dictionary whose
keys are the names of the time zones and whose values are offsets from the Eastern time
zone.
Write a program that converts a time from one time zone to another. The user enters the time
in the usual American way, such as 3:48pm or 11:26am. The first time zone the user enters
is that of the original time and the second is the desired time zone. The possible time zones
are Eastern, Central, Mountain, or Pacific.
Time: 11:48pm
Starting zone: Pacific
Ending zone: Eastern
2:48am
16. (a) Write a program that converts Roman numerals into ordinary numbers. Here are the
conversions: M=1000, D=500, C=100, L=50, X=10, V=5 I=1. Don’t forget about things
like IV being 4 and XL being 40.
(b) Write a program that converts ordinary numbers into Roman numerals
108 CHAPTER 11. DICTIONARIES
Chapter 12
Text Files
There is a ton of interesting data to be found on the internet stored in text files. In this chapter we
will learn how to work with data stored in text files.
Suppose we have a text file called example.txt whose contents are shown below, and we want to
read its contents into Python. There are several ways to do so. We will look at two of them.
Hello.
This is a text file.
Bye!
1. The first way to read a text file uses a list comprehension to load the file line-by-line into a
list:
lines = [line.strip() for line in open( 'example.txt ')]
The list lines is now
[ 'Hello. ', 'This is a text file. ', 'Bye! ']
The string method strip removes any whitespace characters from the beginning and end of
a string. If we had not used it, each line would contain a newline character at the end of the
line. This is usually not what we want.
Note: strip removes whitespace from both the beginning and end of the line. Use rstrip
if you need to preserve whitespace at the beginning of the line.
2. The second way of reading a text file loads the entire file into a string:
s = open( 'example.txt ').read()
The string s is now
'Hello.\nThis is a text file.\nBye! '
109
110 CHAPTER 12. TEXT FILES
Directories
The file is assumed to be in the same directory as your program itself. If it is in a different directory,
then you need to specify that, like below:
s = open( 'c:/users/heinold/desktop/file.txt ').read()
There are also several ways to write to files. We will look at one way here. We will be writing to a
file called writefile.txt.
We first have to open the file. That is what the first line does, with the 'w' indicating that we want
to be able to write to the file. Python creates what is called a file object to represent the file, and we
give that object the name f. This is what we use to refer to the file. To write to the file, we use the
print statement with the optional file argument that specifies the file to write to. When we are
done writing, we should close the file to make sure all of our changes take. Be careful here because
if writefile.txt already exists, its contents will be overwritten.
12.3 Examples
Example 1 Write a program that reads a list of temperatures from a file called temps.txt, con-
verts those temperatures to Fahrenheit, and writes the results to a file called ftemps.txt.
Example 2 In Section 7.6 we wrote a simple quiz game. The questions and answers were both
contained in lists hard-coded into the program. Instead of that, we can store the questions and
answers in files. That way, if you decide to change the questions or answers, you just have to
change their files. Moreover, if you decide to give the program to someone else who doesn’t know
12.4. WORDPLAY 111
Python, they can easily create their own lists of questions and answers. To do this, we just replace
the lines that create the lists with the following:
questions = [line.strip() for line in open( 'questions.txt ')]
answers = [line.strip() for line in open( 'answers.txt ')]
Example 3 Say you have a text file that contains the results of every 2009-10 NCAA basketball
game. (You can find such a file at www.kenpom.com.) A typical line of the file looks like this:
Below is a program that scans through the file to find the most lopsided game, the one where the
winning team had the largest margin of victory.
We use the split method to break each line into a lists of its component parts. The scores are at
indices 2 and 4. To find the maximum difference, we can use a list comprehension to create a list of
all the margins of victories and use max to find the maximum.
The maximum turns out to be 84. Unfortunately, the method above does not tell us anything else
about the game. In order to do that, we resort to the longer way to find maximums, described in
Section 5.5. This allows us to store information about the game as we search for the largest margin
of victory.
biggest_diff = 0
for g in games:
diff = abs(int(g[2])-int(g[4]))
if diff>biggest_diff:
biggest_diff = diff
game_info = g
print(game_info)
12.4 Wordplay
If you like words, you can have a lot of fun with a wordlist, which is a text file where each line
contains a different word. A quick web search will turn up a variety of different wordlists, ranging
from lists of common English words to lists containing practically every English word.
112 CHAPTER 12. TEXT FILES
Assuming the wordlist file is wordlist.txt, we can load the words into a list using the line
below.
wordlist = [line.strip() for line in open( 'wordlist.txt ')]
Note that this and most of the upcoming examples can be done with list comprehensions:
print([word for word in wordlist if len(word)==3])
count = 0
for word in wordlist:
if word[0] in 'aeiou ':
count=count+1
print(100*count/len(wordlist))
Example 4 Print all 7-letter words that start with th and end in ly. Things like this are good for
cheating at crosswords.
i=0
while wordlist[i][0]!= 'q ':
i=i+1
print(wordlist[i:i+10]
12.5. EXERCISES 113
Note this is not a very efficient way of doing things since we have to scan through most of the list.
A binary search would be more efficient, but the above approach still runs almost instantly even
for large files.
Example 6 Find the longest word that can be made using only the letters a, b, c, d, and e.
largest = 0
for word in wordlist:
for c in word:
if c not in 'abcde ':
break
else:
if len(word)>largest:
largest=len(word)
largest_word=word
print(largest_word)
The way this program works is for every word in the wordlist, we use a for/else loop (Section 9.4)
to scan through the word looking checking each character to see if it is an a, b, c, d, or e. If any
letter isn’t one of these, then we break out of the loop and move on to the next word. On the other
hand, if we get all the way through the loop, then we go to else block. In that block, we use a
modification of the technique from Section 5.5 for finding a maximum.
12.5 Exercises
1. You are given a file called class_scores.txt, where each line of the file contains a one-
word username and a test score separated by spaces, like below:.
GWashington 83
JAdams 86
Write code that scans through the file, adds 5 points to each test score, and outputs the user-
names and new test scores to a new file, scores2.txt.
2. You are given a file called grades.txt, where each line of the file contains a one-word stu-
dent username and three test scores separated by spaces, like below:.
GWashington 83 77 54
JAdams 86 69 90
Write code that scans through the file and determines how many students passed all three
tests.
3. You are given a file called logfile.txt that lists log-on and log-off times for users of a
system. A typical line of the file looks like this:
Each line has three entries separated by commas: a username, a log-on time, and a log-off
time. Times are given in 24-hour format. You may assume that all log-ons and log-offs occur
within a single workday.
Write a program that scans through the file and prints out all users who were online for at
least an hour.
4. You are given a file called students.txt. A typical line in the file looks like:
There is a name, an email address, and a phone number, each separated by tabs. Write a
program that reads through the file line-by-line, and for each line, capitalizes the first letter
of the first and last name and adds the area code 301 to the phone number. Your program
should write this to a new file called students2.txt. Here is what the first line of the new
file should look like:
5. You are given a file namelist.txt that contains a bunch of names. Some of the names are
a first name and a last name separated by spaces, like George Washington, while others have
a middle name, like John Quincy Adams. There are no names consisting of just one word or
more than three words. Write a program that asks the user to enter initials, like GW or JQA,
and prints all the names that match those initials. Note that initials like JA should match both
John Adams and John Quincy Adams.
6. You are given a file namelist.txt that contains a bunch of names. Print out all the names
in the list in which the vowels a, e, i, o, and u appear in order (with repeats possible). The first
vowel in the name must be a and after the first u, it is okay for there to be other vowels. An
example is Ace Elvin Coulson.
7. You are given a file called baseball.txt. A typical line of the file starts like below.
Each entry is separated by a tab, \t. The first entry is the player’s name and the second is
their team. Following that are 16 statistics. Home runs are the seventh stat and stolen bases
are the eleventh. Print out all the players who have at least 20 home runs and at least 20 stolen
bases.
8. For this problem, use the file of NCAA basketball scores as described in Section 12.3.
(a) Find the average of the points scored over all the games in the file.
(b) Pick your favorite team and scan through the file to determine how many games they
won and how many games they lost.
(c) Find the team(s) that lost by 30 or more points the most times
(d) Find all the teams that averaged at least 70 points a game.
12.5. EXERCISES 115
(e) Find all the teams that had winning records but were collectively outscored by their
opponents. A team is collectively outscored by their opponents if the total number of
points the team scored over all their games is less than the total number of points their
opponents scored in their games against the team.
9. Benford’s law states that in real data where the values are spread across several orders of
magnitude, about 30% of the values will start with the number 1, whereas only about 4.6%
of the values will start with the number 9. This is contrary to what we might expect, namely
that values starting with 1 and 9 would be equally likely. Using the file expenses.txt which
consists of a number of costs from an expense account, determine what percentage start with
each of the digits 1 through 9. This technique is used by accountants to detect fraud.
10. Wordplay – Use the file wordlist.txt for this problem. Find the following:
(x) All words of the form abcd*dcba, where * is arbitrarily long sequence of letters.
(y) All groups of 5 words, like pat pet pit pot put, where each word is 3 letters, all words share
the same first and last letters, and the middle letter runs through all 5 vowels.
(z) The word that has the most i’s.
11. Write a program to help with word games. The user enters a word and the program uses the
wordlist to determine if the user’s word is a real word or not.
12. Suppose we write all the words in the wordlist backwards and then arrange these backwards
words alphabetically. Write a program that prints the last word in this modified wordlist.
13. Print out all combinations of the string 'Python' plus a three letter English word. Cap-
italize the first letter of the three letter word. Example combinations are 'PythonCat',
'PythonDog', and 'PythonTag'. These are valid combinations because cat, dog, and tag
are English words. On the other hand, 'PythonQqz' would not be a valid combination be-
cause qqz is not an English word. Use a wordlist to determine which three letter combinations
are words.
14. Write a simple spell-checking program. The user should enter a string and the program
should print out a list of all the words it thinks are misspelled. These would be all the words
it cannot find in a wordlist.
15. Crossword cheater: When working on a crossword puzzle, often you will have a word where
you know several of the letters, but not all of them. You can write a computer program to
help you. For the program, the user should be able to input a word with the letters they
know filled in and asterisks for those they don’t know. The program should print out a list
of all words that fit that description. For example, the input th***ly should return all the
words that could work, namely thickly and thirdly.
16. Ask the user to enter several letters. Then find all the words that can be made with those
letters, repeats allowed.
17. Using the wordlist, produce a dictionary whose keys are the letters a through z and whose
values are the percentage of words that use that letter.
18. Using the wordlist, produce a dictionary whose keys are the letters a through z and whose
values are the percentage of total letters in the wordlist that are that letter.
19. Write a program that asks the user for a word and finds all the smaller words that can be
made from the letters of that word. The number of occurrences of a letter in a smaller word
can’t exceed the number of occurrences of the letter in the user’s word.
20. (a) Write a program that reads a file consisting of email addresses, each on its own line.
Your program should print out a string consisting of those email addresses separated by
semicolons.
(b) Write the same program as above, but the new string should contain only those email
addresses that do not end in @prof.college.edu.
12.5. EXERCISES 117
21. The file high_temperatures.txt contains the average high temperatures for each day of
the year in a certain city. Each line of the file consists of the date, written in the month/day
format, followed by a space and the average high temperature for that date. Find the 30-day
period over which there is the biggest increase in the average high temperature.
22. In Chapter 6 there was an exercise about the game Mad Libs. It asked you to make up a story
and leave out some words of the story. Your program should ask the user to enter some words
and tell them what types of words to enter. Then print the full story along with the inserted
words. Rewrite your program from that exercise to read the story from a file. Reading the
story from a file allows people who do not know how to program to use their own stories
with the program without having to change the code.
23. An acronym is an abbreviation that uses the first letter of each word in a phrase. We see them
everywhere. For instance, NCAA for National Collegiate Athletic Association or NBC for
National Broadcasting Company. Write a program where the user enters an acronym and the
program randomly selects words from a wordlist such that the words would fit the acronym.
Below is some typical output generated when I ran the program:
24. This problem is about a version of the game Jotto. The computer chooses a random five-letter
word with no repeat letters. The player gets several turns to try to guess the computer’s
word. On each turn, the player guesses a five-letter word and is told the number of letters
that their guess has in common with the computer’s word.
25. The word part has the interesting property that if you remove its letters one by one, each
resulting step is a real word. For instance, part → pat → pa → a. You may remove the letters in
any order, and the last (single-letter) word needs to be a real word as well. Find all eight-letter
words with this property.
26. Write a program to cheat at the game Scrabble. The user enters a string. Your program should
return a list of all the words that can be created from those seven letters.
118 CHAPTER 12. TEXT FILES
Chapter 13
Functions
Functions are useful for breaking up a large program to make it easier to read and maintain. They
are also useful if you find yourself writing the same code at several different points in your pro-
gram. You can put that code in a function and call the function whenever you want to execute that
code. You can also use functions to create your own utilities, math functions, etc.
13.1 Basics
Functions are defined with the def statement. The statement ends with a colon, and the code that
is part of the function is indented below the def statement. Here we create a simple function that
just prints something.
def print_hello():
print( 'Hello! ')
print_hello()
print( '1234567 ')
print_hello()
Hello!
1234567
Hello!
The first two lines define the function. In the last three lines we call the function twice.
One use for functions is if you are using the same code over and over again in various parts of your
program, you can make your program shorter and easier to understand by putting the code in a
function. For instance, suppose for some reason you need to print a box of stars like the one below
at several points in your program.
119
120 CHAPTER 13. FUNCTIONS
**************
* *
* *
**************
Put the code into a function, and then whenever you need a box, just call the function rather than
typing several lines of redundant code. Here is the function.
def draw_square():
print( '* ' * 15)
print( '* ', ' '*11, '* ')
print( '* ', ' '*11, '* ')
print( '* ' * 15)
One benefit of this is that if you decide to change the size of the box, you just have to modify the
code in the function, whereas if you had copied and pasted the box-drawing code everywhere you
needed it, you would have to change all of them.
13.2 Arguments
def print_hello(n):
print( 'Hello ' * n)
print()
print_hello(3)
print_hello(5)
times = 2
print_hello(times)
When we call the print_hello function with the value 3, that value gets stored in the variable n.
We can then refer to that variable n in our function’s code.
HelloHelloHelloHelloHello
AAAAAAAAAA
Example 1 Here is a simple function that converts temperatures from Celsius to Fahrenheit.
def convert(t):
return t*9/5+32
print(convert(20))
68
The return statement is used to send the result of a function’s calculations back to the caller.
Notice that the function itself does not do any printing. The printing is done outside of the function.
That way, we can do math with the result, like below.
print(convert(20)+5)
If we had just printed the result in the function instead of returning it, the result would have been
printed to the screen and forgotten about, and we would never be able to do anything with it.
Example 2 As another example, the Python math module contains trig functions, but they only
work in radians. Let us write our own sine function that works in degrees.
def deg_sin(x):
return sin(pi*x/180)
Say we want to write a function that solves the system of equations ax + b y = e and c x + d y = f .
It turns out that if there is a unique solution, then it is given by x = (de − b f )/(ad − bc) and
y = (a f − ce)/(ad − bc). We need our function to return both the x and y solutions.
def solve(a,b,c,d,e,f):
x = (d*e-b*f)/(a*d-b*c)
y = (a*f-c*e)/(a*d-b*c)
return [x,y]
122 CHAPTER 13. FUNCTIONS
This method uses the shortcut for assigning to lists that was mentioned in Section 10.3.
The same effect can be achieved with an if/else statement, but in some cases, using return can
make your code simpler and more readable.
You can specify a default value for an argument. This makes it optional, and if the caller decides
not to use it, then it takes the default value. Here is an example:
HelloHelloHelloHelloHello
Hello
Default arguments need to come at the end of the function definition, after all of the non-default
arguments.
Keyword arguments A related concept to default arguments is keyword arguments. Say we have
the following function definition:
def fancy_print(text, color, background, style, justify):
Every time you call this function, you have to remember the correct order of the arguments. Fortu-
nately, Python allows you to name the arguments when calling the function, as shown below:
fancy_print(text= 'Hi ', color= 'yellow ', background= 'black ',
style= 'bold ', justify= 'left ')
13.5. LOCAL VARIABLES 123
As we can see, the order of the arguments does not matter when you use keyword arguments.
When defining the function, it would be a good idea to give defaults. For instance, most of the time,
the caller would want left justification, a white background, etc. Using these values as defaults
means the caller does not have to specify every single argument every time they call the function.
Here is a example:
Note We have actually seen default and keyword arguments before—the sep, end and file
arguments of the print function.
Let’s say we have two functions like the ones below that each use a variable i:
def func1():
for i in range(10):
print(i)
def func2():
i=100
func1()
print(i)
A problem that could arise here is that when we call func1, we might mess up the value of i
in func2. In a large program it would be a nightmare trying to make sure that we don’t repeat
variable names in different functions, and, fortunately, we don’t have to worry about this. When
a variable is defined inside a function, it is local to that function, which means it essentially does
not exist outside that function. This way each function can define its own variables and not have
to worry about if those variable names are used in other functions.
Global variables On the other hand, sometimes you actually do want the same variable to be
available to multiple functions. Such a variable is called a global variable. You have to be careful
using global variables, especially in larger programs, but a few global variables used judiciously
are fine in smaller programs. Here is a short example:
124 CHAPTER 13. FUNCTIONS
def reset():
global time_left
time_left = 0
def print_time():
print(time_left)
time_left=30
In this program we have a variable time_left that we would like multiple functions to have
access to. If a function wants to change the value of that variable, we need to tell the function that
time_left is a global variable. We use a global statement in the function to do this. On the other
hand, if we just want to use the value of the global variable, we do not need a global statement.
Arguments We finish the chapter with a bit of a technical detail. You can skip this section for the
time being if you don’t want to worry about details right now. Here are two simple functions:
def func1(x):
x = x + 1
def func2(L):
L = L + [1]
a=3
M=[1,2,3]
func1(a)
func2(M)
When we call func1 with a and func2 with L, a question arises: do the functions change the
values of a and L? The answer may surprise you. The value of a is unchanged, but the value of L is
changed. The reason has to do with a difference in the way that Python handles numbers and lists.
Lists are said to be mutable objects, meaning they can be changed, whereas numbers and strings are
immutable, meaning they cannot be changed. There is more on this in Section 19.1.
If we want to reverse the behavior of the above example so that a is modified and L is not, do the
following:
def func1(x):
x = x + 1
return x
def func2(L):
copy = L[:]
copy = copy + [1]
a=3
M=[1,2,3]
a=func1(a) # note change on this line
13.6. EXERCISES 125
func2(M)
13.6 Exercises
1. Write a function called rectangle that takes two integers m and n as arguments and prints
out an m × n box consisting of asterisks. Shown below is the output of rectangle(2,4)
****
****
2. (a) Write a function called add_excitement that takes a list of strings and adds an excla-
mation point (!) to the end of each string in the list. The program should modify the
original list and not return anything.
(b) Write the same function except that it should not modify the original list and should
instead return a new list.
3. Write a function called sum_digits that is given an integer num and returns the sum of the
digits of num.
4. The digital root of a number n is obtained as follows: Add up the digits n to get a new number.
Add up the digits of that to get another new number. Keep doing this until you get a number
that has only one digit. That number is the digital root.
For example, if n = 45893, we add up the digits to get 4 + 5 + 8 + 9 + 3 = 29. We then add up
the digits of 29 to get 2 + 9 = 11. We then add up the digits of 11 to get 1 + 1 = 2. Since 2 has
only one digit, 2 is our digital root.
Write a function that returns the digital root of an integer n. [Note: there is a shortcut, where
the digital root is equal to n mod 9, but do not use that here.]
5. Write a function called first_diff that is given two strings and returns the first location in
which the strings differ. If the strings are identical, it should return -1.
6. Write a function called binom that takes two integers n and k and returns the binomial coef-
ficient nk . The definition is nk = k!(n−k)!
n!
.
7. Write a function that takes an integer n and returns a random integer with exactly n digits. For
instance, if n is 3, then 125 and 593 would be valid return values, but 093 would not because
that is really 93, which is a two-digit number.
8. Write a function called number_of_factors that takes an integer and returns how many
factors the number has.
9. Write a function called factors that takes an integer and returns a list of its factors.
10. Write a function called closest that takes a list of numbers L and a number n and returns
the largest element in L that is not larger than n. For instance, if L=[1,6,3,9,11] and n=8,
then the function should return 6, because 6 is the closest thing in L to 8 that is not larger than
8. Don’t worry about if all of the things in L are smaller than n.
126 CHAPTER 13. FUNCTIONS
11. Write a function called matches that takes two strings as arguments and returns how many
matches there are between the strings. A match is where the two strings have the same char-
acter at the same index. For instance, 'python' and 'path' match in the first, third, and
fourth characters, so the function should return 3.
12. Recall that if s is a string, then s.find('a') will find the location of the first a in s. The
problem is that it does not find the location of every a. Write a function called findall that
given a string and a single character, returns a list containing all of the locations of that char-
acter in the string. It should return an empty list if there are no occurrences of the character
in the string.
13. Write a function called change_case that given a string, returns a string with each upper
case letter replaced by a lower case letter and vice-versa.
14. Write a function called is_sorted that is given a list and returns True if the list is sorted
and False otherwise.
15. Write a function called root that is given a number x and an integer n and returns x 1/n . In
the function definition, set the default value of n to 2.
16. Write a function called one_away that takes two strings and returns True if the strings are of
the same length and differ in exactly one letter, like bike/hike or water/wafer.
17. (a) Write a function called primes that is given a number n and returns a list of the first n
primes. Let the default value of n be 100.
(b) Modify the function above so that there is an optional argument called start that allows
the list to start at a value other than 2. The function should return the first n primes that
are greater than or equal to start. The default value of start should be 2.
18. Our number system is called base 10 because we have ten digits: 0, 1, . . . , 9. Some cultures,
including the Mayans and Celts, used a base 20 system. In one version of this system, the 20
digits are represented by the letters A through T. Here is a table showing a few conversions:
10 20 10 20 10 20 10 20
0 A 8 I 16 Q 39 BT
1 B 9 J 17 R 40 CA
2 C 10 K 18 S 41 CB
3 D 11 L 19 T 60 DA
4 E 12 M 20 BA 399 TT
5 F 13 N 21 BB 400 BAA
6 G 14 O 22 BC 401 BAB
7 H 15 P 23 BD 402 BAC
Write a function called base20 that converts a base 10 number to base 20. It should return
the result as a string of base 20 digits. One way to convert is to find the remainder when
the number is divided by 20, then divide the number by 20, and repeat the process until the
number is 0. The remainders are the base 20 digits in reverse order, though you have to
convert them into their letter equivalents.
13.6. EXERCISES 127
19. Write a function called verbose that, given an integer less than 1015 , returns the name of
the integer in English. As an example, verbose(123456) should return one hundred
twenty-three thousand, four hundred fifty-six.
20. Write a function called merge that takes two already sorted lists of possibly different lengths,
and merges them into a single sorted list.
21. In Chapter 12, the way we checked to see if a word w was a real word was:
if w in words:
where words was the list of words generated from a wordlist. This is unfortunately slow, but
there is a faster way, called a binary search. To implement a binary search in a function, start
by comparing w with the middle entry in words. If they are equal, then you are done and
the function should return True. On the other hand, if w comes before the middle entry, then
search the first half of the list. If it comes after the middle entry, then search the second half of
the list. Then repeat the process on the appropriate half of the list and continue until the word
is found or there is nothing left to search, in which case the function short return False. The
< and > operators can be used to alphabetically compare two strings.
22. A Tic-tac-toe board can be represented be a 3 × 3 two-dimensional list, where zeroes stand for
empty cells, ones stand for X’s and twos stand for O’s.
(a) Write a function that is given such a list and randomly chooses a spot in which to place
a 2. The spot chosen must currently be a 0 and a spot must be chosen.
(b) Write a function that is given such a list and checks to see if someone has won. Return
True if there is a winner and False otherwise.
23. Write a function that is given a 9 × 9 potentially solved Sudoku and returns True if it is
solved correctly and False if there is a mistake. The Sudoku is correctly solved if there are
no repeated numbers in any row or any column or in any of the nine “blocks.”
128 CHAPTER 13. FUNCTIONS
Chapter 14
Object-Oriented Programming
About a year or so after I started programming, I decided to make a game to play Wheel of Fortune.
I wrote the program in the BASIC programming language and it got to be pretty large, a couple
thousand lines. It mostly worked, but whenever I tried to fix something, my fix would break
something in a completely different part of the program. I would then fix that and break something
else. Eventually I got the program working, but after a while I was afraid to even touch it.
The problem with the program was that each part of the program had access to the variables from
the other parts. A change of a variable in one part would mess up things in the others. One solu-
tion to this type of problem is object-oriented programming. One of its chief benefits is encapsulation,
where you divide your program into pieces and each piece internally operates independently of
the others. The pieces interact with each other, but they don’t need to know exactly how each one
accomplishes its tasks. This requires some planning and set-up time before you start your program,
and so it is not always appropriate for short programs, like many of the ones that we have written
so far.
We will just cover the basics of object-oriented programming here. Object-oriented programming
is used extensively in software design and I would recommend picking up another book on pro-
gramming or software design to learn more about designing programs in an object-oriented way.
Python is an object-oriented programming language, and we have in fact been using many object-
oriented concepts already. The key notion is that of an object. An object consists of two things:
data and functions (called methods) that work with that data. As an example, strings in Python are
objects. The data of the string object is the actual characters that make up that string. The methods
are things like lower, replace, and split. In Python, everything is an object. That includes not
only strings and lists, but also integers, floats, and even functions themselves.
129
130 CHAPTER 14. OBJECT-ORIENTED PROGRAMMING
A class is a template for objects. It contains the code for all the object’s methods.
A simple example Here is a simple example to demonstrate what a class looks like. It does not
do anything interesting.
class Example:
def __init__(self, a, b):
self.a = a
self.b = b
def add(self):
return self.a + self.b
e = Example(8, 6)
print(e.add())
• To create a class, we use the class statement. Class names usually start with a capital.
• Most classes will have a method called __init__. The underscores indicate that it is a special
kind of method. It is called a constructor, and it is automatically called when someone creates
a new object from your class. The constructor is usually used to set up the class’s variables. In
the above program, the constructor takes two values, a and b, and assigns the class variables
a and b to those values.
• The first argument to every method in your class is a special variable called self. Every
time your class refers to one of its variables or methods, it must precede them by self. The
purpose of self is to distinguish your class’s variables and methods from other variables
and functions in the program.
• To create a new object from the class, you call the class name along with any values that you
want to send to the constructor. You will usually want to assign it to a variable name. This is
what the line e=Example(8,6) does.
A more practical example Here is a class called Analyzer that performs some simple analysis
on a string. There are methods to return how many words are in the string, how many are of a
given length, and how many start with a given string.
class Analyzer:
def __init__(self, s):
for c in punctuation:
s = s.replace(c, '')
14.2. CREATING YOUR OWN CLASSES 131
s = s.lower()
self.words = s.split()
def number_of_words(self):
return len(self.words)
• One reason why we would wrap this code up in a class is we can then use it a variety of
different programs. It is also good just for organizing things. If all our program is doing is
just analyzing some strings, then there’s not too much of a point of writing a class, but if this
were to be a part of a larger program, then using a class provides a nice way to separate the
Analyzer code from the rest of the code. It also means that if we were to change the internals
of the Analyzer class, the rest of the program would not be affected as long as the interface,
the way the rest of the program interacts with the class, does not change. Also, the Analyzer
class can be imported as-is in other programs.
14.3 Inheritance
In object-oriented programming there is a concept called inheritance where you can create a class
that builds off of another class. When you do this, the new class gets all of the variables and
methods of the class it is inheriting from (called the base class). It can then define additional variables
and methods that are not present in the base class, and it can also override some of the methods of
the base class. That is, it can rewrite them to suit its own purposes. Here is a simple example:
class Parent:
def __init__(self, a):
self.a = a
def method1(self):
return self.a*2
def method2(self):
return self.a+ '!!! '
class Child(Parent):
def __init__(self, a, b):
self.a = a
self.b = b
def method1(self):
return self.a*7
def method3(self):
return self.a + self.b
We see in the example above that the child has overridden the parent’s method1, causing it to now
repeat the string seven times. The child has inherited the parent’s method2, so it can use it without
having to define it. The child also adds some features to the parent class, namely a new variable b
and a new method, method3.
A note about syntax: when inheriting from a class, you indicate the parent class in parentheses in
the class statement.
14.4. A PLAYING-CARD EXAMPLE 133
If the child class adds some new variables, it can call the parent class’s constructor as demonstrated
below. Another use is if the child class just wants to add on to one of the parent’s methods. In the
example below, the child’s print_var method calls the parent’s print_var method and adds an
additional line.
class Parent:
def __init__(self, a):
self.a = a
def print_var(self):
print("The value of this class 's variables are:")
print(self.a)
class Child(Parent):
def __init__(self, a, b):
Parent.__init__(self, a)
self.b = b
def print_var(self):
Parent.print_var(self)
print(self.b)
Note You can also inherit from Python built-in types, like strings (str) and lists (list), as well
as any classes defined in the various modules that come with Python.
Note Your code can inherit from more than one class at a time, though this can be a little tricky.
In this section we will show how to design a program with classes. We will create a simple hi-lo
card game where the user is given a card and they have to say if the next card will be higher or
lower than it. This game could easily be done without classes, but we will create classes to represent
a card and a deck of cards, and these classes can be reused in other card games.
We start with a class for a playing card. The data associated with a card consists of its value (2
through 14) and its suit. The Card class below has only one method, __str__. This is a special
method that, among other things, tells the print function how to print a Card object.
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __str__(self):
names = [ 'Jack ', 'Queen ', 'King ', 'Ace ']
if self.value <= 10:
134 CHAPTER 14. OBJECT-ORIENTED PROGRAMMING
Next we have a class to represent a group of cards. Its data consists of a list of Card objects. It
has a number of methods: nextCard which removes the first card from the list and returns it;
hasCard which returns True or False depending on if there are any cards left in the list; size,
which returns how many cards are in the list; and shuffle, which shuffles the list.
import random
class Card_group:
def __init__(self, cards=[]):
self.cards = cards
def nextCard(self):
return self.cards.pop(0)
def hasCard(self):
return len(self.cards)>0
def size(self):
return len(self.cards)
def shuffle(self):
random.shuffle(self.cards)
We have one more class Standard_deck, which inherits from Card_group. The idea here is that
Card_group represents an arbitrary group of cards, and Standard_deck represents a specific
group of cards, namely the standard deck of 52 cards used in most card games.
class Standard_deck(Card_group):
def __init__(self):
self.cards = []
for s in [ 'Hearts ', 'Diamonds ', 'Clubs ', 'Spades ']:
for v in range(2,15):
self.cards.append(Card(v, s))
Suppose we had just created a single class that represented a standard deck along with all the
common operations like shuffling. If we wanted to create a new class for a Pinochle game or some
other game that doesn’t use the standard deck, then we would have to copy and paste the standard
deck code and modify lots of things. By doing things more generally, like we’ve done here, each
time we want a new type of deck, we can build off of (inherit from) what is in Card_group. For
instance, a Pinochle deck class would look like this:
class Pinochle_deck(Card_group):
def __init__(self):
self.cards = []
for s in [ 'Hearts ', 'Diamonds ', 'Clubs ', 'Spades ']*2:
14.4. A PLAYING-CARD EXAMPLE 135
for v in range(9,15):
self.cards.append(Card(v, s))
A Pinochle deck has only nines, tens, jacks, queens, kings, and aces. There are two copies of each
card in each suit.
Here is the hi-low program that uses the classes we have developed here. One way to think of what
we have done with the classes is that we have built up a miniature card programming language,
where we can think about how a card game works and not have to worry about exactly how cards
are shuffled or dealt or whatever, since that is wrapped up into the classes. For the hi-low game,
we get a new deck of cards, shuffle it, and then deal out the cards one at a time. When we run out
of cards, we get a new deck and shuffle it. A nice feature of this game is that it deals out all 52 cards
of a deck, so a player can use their memory to help them play the game.
deck = Standard_deck()
deck.shuffle()
new_card = deck.nextCard()
print( '\n ', new_card)
choice = input("Higher (h) or lower (l): ")
streak = 0
old_card = new_card
new_card = deck.nextCard()
King of Clubs
Higher (h) or lower (l): l
Right! That's 1 in a row!
2 of Spades
136 CHAPTER 14. OBJECT-ORIENTED PROGRAMMING
In this section we create an object-oriented Tic-tac-toe game. We use a class to wrap up the logic of
the game. The class contains two variables, an integer representing the current player, and a 3 × 3
list representing the board. The board variable consists of zeros, ones, and twos. Zeros represent
an open spot, while ones and twos represent spots marked by players 1 and 2, respectively. There
are four methods:
• get_open_spots — returns a list of the places on the board that have not yet been marked
by players
• is_valid_move — takes a row and a column representing a potential move, and returns
True if move is allowed and False otherwise
• make_move — takes a row and a column representing a potential move, calls is_valid_move
to see if the move is okay, and if it is, sets the board array accordingly and changes the player
• check_for_winner — scans through the board list and returns 1 if player 1 has won, 2 if
player 2 has won, 0 if there are no moves remaining and no winner, and -1 if the game should
continue
class tic_tac_toe:
def __init__(self):
self.B = [[0,0,0],
[0,0,0],
[0,0,0]]
self.player = 1
def get_open_spots(self):
return [[r,c] for r in range(3) for c in range(3)
if self.B[r][c]==0]
def is_valid_move(self,r,c):
if 0<=r<=2 and 0<=c<=2 and self.B[r][c]==0:
return True
return False
def make_move(self,r,c):
if self.is_valid_move(r,c):
self.B[r][c] = self.player
self.player = (self.player+2)%2 + 1
def check_for_winner(self):
14.5. A TIC-TAC-TOE EXAMPLE 137
for c in range(3):
if self.B[0][c]==self.B[1][c]==self.B[2][c]!=0:
return self.B[0][c]
for r in range(3):
if self.B[r][0]==self.B[r][1]==self.B[r][2]!=0:
return self.B[r][0]
if self.B[0][0]==self.B[1][1]==self.B[2][2]!=0:
return self.B[0][0]
if self.B[2][0]==self.B[1][1]==self.B[0][2]!=0:
return self.B[2][0]
if self.get_open_spots()==[]:
return 0
return -1
This class consists of the logic of the game. There is nothing in the class that is specific to the user
interface. Below we have a text-based interface using print and input statements. If we decide to
use a graphical interface, we can use the Tic_tac_toe class without having to change anything
about it. Note that the get_open_spots method is not used by this program. It is useful, however,
if you want to implement a computer player. A simple computer player would call that method
and use random.choice method to choose a random element from the returned list of spots.
def print_board():
chars = [ '- ', 'X ', 'O ']
for r in range(3):
for c in range(3):
print(chars[game.B[r][c]], end= ' ')
print()
game = tic_tac_toe()
while game.check_for_winner()==-1:
print_board()
r,c = eval(input( 'Enter spot, player ' + str(game.player) + ': '))
game.make_move(r,c)
print_board()
x = game.check_for_winner()
if x==0:
print("It 's a draw.")
else:
print( 'Player ', x, 'wins! ')
- - -
- - -
- - -
Enter spot, player 1: 1,1
- - -
- X -
- - -
138 CHAPTER 14. OBJECT-ORIENTED PROGRAMMING
• Copying objects — If you want to make a copy of an object x, it is not enough to do the
following:
x_copy = x
The reason is discussed in Section 19.1. Instead, do the following:
from copy import copy
x_copy = copy(x)
• Keeping your code in multiple files — If you want to reuse a class in several programs, you
do not have to copy and paste the code into each. You can save it in a file and use an import
statement to import it into your programs. The file will need to be somewhere your program
can find it, like in the same directory.
from analyzer import Analyzer
14.7 Exercises
1. Write a class called Investment with fields called principal and interest. The construc-
tor should set the values of those fields. There should be a method called value_after that
returns the value of the investment after n years. The formula for this is p(1 + i)n , where p is
the principal, and i is the interest rate. It should also use the special method __str__ so that
printing the object will result in something like below:
2. Write a class called Product. The class should have fields called name, amount, and price,
holding the product’s name, the number of items of that product in stock, and the regular
price of the product. There should be a method get_price that receives the number of
items to be bought and returns a the cost of buying that many items, where the regular price
14.7. EXERCISES 139
is charged for orders of less than 10 items, a 10% discount is applied for orders of between
10 and 99 items, and a 20% discount is applied for orders of 100 or more items. There should
also be a method called make_purchase that receives the number of items to be bought and
decreases amount by that much.
3. Write a class called Password_manager. The class should have a list called old_passwords
that holds all of the user’s past passwords. The last item of the list is the user’s current pass-
word. There should be a method called get_password that returns the current password
and a method called set_password that sets the user’s password. The set_password
method should only change the password if the attempted password is different from all
the user’s past passwords. Finally, create a method called is_correct that receives a string
and returns a boolean True or False depending on whether the string is equal to the current
password or not.
4. Write a class called Time whose only field is a time in seconds. It should have a method called
convert_to_minutes that returns a string of minutes and seconds formatted as in the fol-
lowing example: if seconds is 230, the method should return '5:50'. It should also have
a method called convert_to_hours that returns a string of hours, minutes, and seconds
formatted analogously to the previous method.
5. Write a class called Wordplay. It should have a field that holds a list of words. The user
of the class should pass the list of words they want to use to the class. There should be the
following methods:
6. Write a class called Converter. The user will pass a length and a unit when declaring an
object from the class—for example, c = Converter(9,'inches'). The possible units are
inches, feet, yards, miles, kilometers, meters, centimeters, and millimeters. For each of these
units there should be a method that returns the length converted into those units. For exam-
ple, using the Converter object created above, the user could call c.feet() and should get
0.75 as the result.
7. Use the Standard_deck class of this section to create a simplified version of the game War.
In this game, there are two players. Each starts with half of a deck. The players each deal
the top card from their decks and whoever has the higher card wins the other player’s cards
and adds them to the bottom of his deck. If there is a tie, the two cards are eliminated from
play (this differs from the actual game, but is simpler to program). The game ends when one
player runs out of cards.
140 CHAPTER 14. OBJECT-ORIENTED PROGRAMMING
8. Write a class that inherits from the Card_group class of this chapter. The class should rep-
resent a deck of cards that contains only hearts and spaces, with only the cards 2 through 10
in each suit. Add a method to the class called next2 that returns the top two cards from the
deck.
9. Write a class called Rock_paper_scissors that implements the logic of the game Rock-
paper-scissors. For this game the user plays against the computer for a certain number of
rounds. Your class should have fields for the how many rounds there will be, the current
round number, and the number of wins each player has. There should be methods for getting
the computer’s choice, finding the winner of a round, and checking to see if someone has one
the (entire) game. You may want more methods.
10. (a) Write a class called Connect4 that implements the logic of a Connect4 game. Use the
Tic_tac_toe class from this chapter as a starting point.
(b) Use the Connect4 class to create a simple text-based version of the game.
11. Write a class called Poker_hand that has a field that is a list of Card objects. There should be
the following self-explanatory methods:
There should also be a method called best that returns a string indicating what the best hand
is that can be made from those cards.