Computer Major Sem 1
Computer Major Sem 1
The first goal of this book is to teach you how to program in Python. But learning to
program means learning a new way to think, so the second goal of this book is to help
you think like a computer scientist. This way of thinking combines some of the best
features of mathematics, engineering, and natural science. Like mathematicians, com‐
puter scientists use formal languages to denote ideas—specifically computations. Like
engineers, they design things, assembling components into systems and evaluating
trade-offs among alternatives. Like scientists, they observe the behavior of complex
systems, form hypotheses, and test predictions.
We will start with the most basic elements of programming and work our way up. In
this chapter, we’ll see how Python represents numbers, letters, and words. And you’ll
learn to perform arithmetic operations.
You will also start to learn the vocabulary of programming, including terms like oper‐
ator, expression, value, and type. This vocabulary is important—you will need it to
understand the rest of the book, to communicate with other programmers, and to use
and understand virtual assistants.
Arithmetic Operators
An arithmetic operator is a symbol that represents an arithmetic computation. For
example, the plus sign, +, performs addition:
30 + 12
42
1
The minus sign, –, is the operator that performs subtraction:
43 - 1
42
6 * 7
42
84 / 2
42.0
Notice that the result of the division is 42.0 rather than 42. That’s because there are
two types of numbers in Python:
If you add, subtract, or multiply two integers, the result is an integer. But if you divide
two integers, the result is a floating-point number. Python provides another opera‐
tor, //, that performs integer division. The result of integer division is always an
integer:
84 // 2
42
Integer division is also called “floor division” because it always rounds down (toward
the “floor”):
85 // 2
42
7 ** 2
49
In some other languages, the caret, ^, is used for exponentiation, but in Python it is a
bitwise operator called XOR. If you are not familiar with bitwise operators, the result
might be unexpected:
7 ^ 2
I won’t cover bitwise operators in this book, but you can read about them at http://
wiki.python.org/moin/BitwiseOperators.
Expressions
A collection of operators and numbers is called an expression. An expression can
contain any number of operators and numbers. For example, here’s an expression that
contains two operators:
6 + 6 ** 2
42
Notice that exponentiation happens before addition. Python follows the order of
operations you might have learned in a math class: exponentiation happens before
multiplication and division, which happen before addition and subtraction.
In the following example, multiplication happens before addition:
12 + 5 * 6
42
If you want the addition to happen first, you can use parentheses:
(12 + 5) * 6
102
Every expression has a value. For example, the expression 6 * 7 has the value 42.
Expressions | 3
Arithmetic Functions
In addition to the arithmetic operators, Python provides a few functions that work
with numbers. For example, the round function takes a floating-point number and
rounds it off to the nearest whole number:
round(42.4)
42
round(42.6)
43
The abs function computes the absolute value of a number. For a positive number,
the absolute value is the number itself:
abs(42)
42
abs(-42)
42
When we use a function like this, we say we’re calling the function. An expression
that calls a function is a function call.
When you call a function, the parentheses are required. If you leave them out, you get
an error message:
abs 42
You can ignore the first line of this message; it doesn’t contain any information we
need to understand right now. The second line is the code that contains the error,
with a caret (^) beneath it to indicate where the error was discovered.
abs
A function name all by itself is a legal expression that has a value. When it’s displayed,
the value indicates that abs is a function, and it includes some additional information
I’ll explain later.
Strings
In addition to numbers, Python can also represent sequences of letters, which are
called strings because the letters are strung together like beads on a necklace. To write
a string, we can put a sequence of letters inside straight quotation marks:
'Hello'
'Hello'
"world"
'world'
Double quotes make it easy to write a string that contains an apostrophe, which is the
same symbol as a straight quote:
'Well, '
'Well, '
Strings | 5
The + operator works with strings; it joins two strings into a single string, which is
called concatenation:
The * operator also works with strings; it makes multiple copies of a string and con‐
catenates them:
'Spam, ' * 4
len('Spam')
Notice that len counts the letters between the quotes, but not the quotes.
When you create a string, be sure to use straight quotes. The backquote, also known
as a backtick, causes a syntax error:
`Hello`
• 2 is an integer,
• 42.0 is a floating-point number, and
• 'Hello' is a string.
type(2)
int
type(42.0)
float
type('Hello, World!')
str
The types int, float, and str can be used as functions. For example, int can take a
floating-point number and convert it to an integer (always rounding down):
int(42.9)
42
float(42)
42.0
Now, here’s something that can be confusing. What do you get if you put a sequence
of digits in quotes?
'126'
'126'
type('126')
str
'126' / 3
This example generates a TypeError, which means that the values in the expression,
which are called operands, have the wrong type. The error message indicates that
the / operator does not support the types of these values, which are str and int.
If you have a string that contains digits, you can use int to convert it to an integer:
int('126') / 3
42.0
If you have a string that contains digits and a decimal point, you can use float to
convert it to a floating-point number:
float('12.6')
12.6
When you write a large integer, you might be tempted to use commas between groups
of digits, as in 1,000,000. This is a legal expression in Python, but the result is not an
integer:
1,000,000
(1, 0, 0)
1_000_000
1000000
Debugging
Programmers make mistakes. For whimsical reasons, programming errors are called
bugs and the process of tracking them down is called debugging.
Programming, and especially debugging, sometimes brings out strong emotions. If
you are struggling with a difficult bug, you might feel angry, sad, or embarrassed.
Preparing for these reactions might help you deal with them. One approach is to
think of the computer as an employee with certain strengths, like speed and
Debugging | 9
precision, and particular weaknesses, like lack of empathy and an inability to grasp
the big picture.
Your job is to be a good manager: find ways to take advantage of the strengths and
mitigate the weaknesses. And find ways to use your emotions to engage with the
problem, without letting your reactions interfere with your ability to work effectively.
Learning to debug can be frustrating, but it is a valuable skill that is useful for many
activities beyond programming. At the end of each chapter there is a section, like this
one, with my suggestions for debugging. I hope they help!
Glossary
arithmetic operator: A symbol, like + and *, that denotes an arithmetic operation
like addition or multiplication.
integer: A type that represents whole numbers.
floating-point: A type that represents numbers with fractional parts.
integer division: An operator, //, that divides two numbers and rounds down to an
integer.
expression: A combination of variables, values, and operators.
value: An integer, floating-point number, or string—or one of other kinds of values
we will see later.
function: A named sequence of statements that performs some useful operation.
Functions may or may not take arguments and may or may not produce a result.
function call: An expression—or part of an expression—that runs a function. It con‐
sists of the function name followed by an argument list in parentheses.
syntax error: An error in a program that makes it impossible to parse—and therefore
impossible to run.
string: A type that represents sequences of characters.
concatenation: Joining two strings end to end.
type: A category of values. The types we have seen so far are integers (type int),
floating-point numbers (type float), and strings (type str).
operand: One of the values on which an operator operates.
natural language: Any of the languages that people speak that evolved naturally.
Exercises
Ask a Virtual Assistant
As you work through this book, there are several ways you can use a virtual assistant
or chatbot to help you learn:
• If you want to learn more about a topic in the chapter, or anything is unclear, you
can ask for an explanation.
• If you are having a hard time with any of the exercises, you can ask for help.
In each chapter, I’ll suggest exercises you can do with a virtual assistant, but I encour‐
age you to try things on your own and see what works for you.
Here are some topics you could ask a virtual assistant about:
• Earlier I mentioned bitwise operators but I didn’t explain why the value of 7 ^ 2
is 5. Try asking “What are the bitwise operators in Python?” or “What is the value
of 7 XOR 2?”
• I also mentioned the order of operations. For more details, ask “What is the order
of operations in Python?”
• The round function, which we used to round a floating-point number to the
nearest whole number, can take a second argument. Try asking “What are the
arguments of the round function?” or “How do I round pi off to three decimal
places?”
• There’s one more arithmetic operator I didn’t mention; try asking “What is the
modulus operator in Python?”
Most virtual assistants know about Python, so they answer questions like this pretty
reliably. But remember that these tools make mistakes. If you get code from a chatbot,
test it!
Exercises | 11
Exercise
You might wonder what round does if a number ends in 0.5. The answer is that it
sometimes rounds up and sometimes rounds down. Try these examples and see if you
can figure out what rule it follows:
round(42.5)
42
round(43.5)
44
If you are curious, ask a virtual assistant, “If a number ends in 0.5, does Python round
up or down?”
Exercise
When you learn about a new feature, you should try it out and make mistakes on
purpose. That way, you learn the error messages, and when you see them again, you
will know what they mean. It is better to make mistakes now and deliberately than
later and accidentally.
1. You can use a minus sign to make a negative number like -2. What happens if
you put a plus sign before a number? What about 2++2?
2. What happens if you have two values with no operator between them, like 4 2?
3. If you call a function like round(42.5), what happens if you leave out one or
both parentheses?
Exercise
Recall that every expression has a value, every value has a type, and we can use the
type function to find the type of any value.
What is the type of the value of the following expressions? Make your best guess for
each one, and then use type to find out.
• 765 • abs(-7.0)
• 2.718 • abs
• '2 pi' • int
• abs(-7) • type
If you already know about variables, you can use them for this exercise. If you don’t,
you can do the exercise without them—and then we’ll see them in the next chapter.
Exercises | 13
CHAPTER 2
Variables and Statements
In the previous chapter, we used operators to write expressions that perform arith‐
metic computations.
In this chapter, you’ll learn about variables and statements, the import statement, and
the print function. And I’ll introduce more of the vocabulary we use to talk about
programs, including “argument” and “module.”
Variables
A variable is a name that refers to a value. To create a variable, we can write an
assignment statement like this:
n = 17
An assignment statement has three parts: the name of the variable on the left, the
equals operator, =, and an expression on the right. In this example, the expression is
an integer. In the following example, the expression is a floating-point number:
pi = 3.141592653589793
When you run an assignment statement, there is no output. Python creates the vari‐
able and gives it a value, but the assignment statement has no visible effect. However,
after creating a variable, you can use it as an expression. So we can display the value
of message like this:
15
message
You can also use a variable as part of an expression with arithmetic operators:
n + 25
42
2 * pi
6.283185307179586
round(pi)
len(message)
42
State Diagrams
A common way to represent variables on paper is to write the name with an arrow
pointing to its value:
This kind of figure is called a state diagram because it shows what state each of the
variables is in (think of it as the variable’s state of mind). We’ll use state diagrams
throughout the book to represent a model of how Python stores variables and their
values.
Variable Names
Variable names can be as long as you like. They can contain both letters and numbers,
but they can’t begin with a number. It is legal to use uppercase letters, but it is conven‐
tional to use only lowercase for variable names.
million! = 1000000
It turns out that class is a keyword, which is a special word used to specify the struc‐
ture of a program. Keywords can’t be used as variable names.
Here’s a complete list of Python’s keywords:
False await else import pass
None break except in raise
True class finally is return
and continue for lambda try
as def from nonlocal while
assert del global not with
async elif if or yield
You don’t have to memorize this list. In most development environments, keywords
are displayed in a different color; if you try to use one as a variable name, you’ll know.
Variable Names | 17
The import Statement
In order to use some Python features, you have to import them. For example, the fol‐
lowing statement imports the math module:
import math
math.pi
3.141592653589793
To use a variable in a module, you have to use the dot operator (.) between the name
of the module and the name of the variable.
The math module also contains functions. For example, sqrt computes square roots:
math.sqrt(25)
5.0
math.pow(5, 2)
25.0
At this point we’ve seen two ways to raise a number to a power: we can use the
math.pow function or the exponentiation operator, **. Either one is fine, but the
operator is used more often than the function.
19 + n + round(math.pi) * 2
42
n = 17
Similarly, an import statement has an effect—it imports a module so we can use the
values and functions it contains—but it has no visible effect:
import math
n + 1
18
But if you evaluate more than one expression, only the value of the last one is dis‐
played:
n + 2
n + 3
20
To display more than one value, you can use the print function:
print(n+2)
print(n+3)
19
20
Notice that the print function puts a space between the values.
Arguments
When you call a function, the expression in parentheses is called an argument. Nor‐
mally I would explain why, but in this case the technical meaning of a term has
almost nothing to do with the common meaning of the word, so I won’t even try.
Some of the functions we’ve seen so far take only one argument, like int:
int('101')
101
math.pow(5, 2)
25.0
Some can take additional arguments that are optional. For example, int can take a
second argument that specifies the base of the number:
int('101', 2)
The sequence of digits 101 in base 2 represents the number 5 in base 10.
round also takes an optional second argument, which is the number of decimal places
to round off to:
round(math.pi, 3)
3.142
If you call a function and provide too many arguments, that’s a TypeError:
float('123.0', 2)
math.pow(2)
And if you provide an argument with a type the function can’t handle, that’s a Type
Error, too:
math.sqrt('123')
This kind of checking can be annoying when you are getting started, but it helps you
detect and correct errors.
Comments
As programs get bigger and more complicated, they get more difficult to read. Formal
languages are dense, and it is often difficult to look at a piece of code and figure out
what it is doing and why.
For this reason, it is a good idea to add notes to your programs to explain in natural
language what the program is doing. These notes are called comments, and they start
with the # symbol:
Comments | 21
In this case, the comment appears on a line by itself. You can also put comments at
the end of a line:
Everything from the # to the end of the line is ignored—it has no effect on the execu‐
tion of the program. Comments are most useful when they document non-obvious
features of the code. It is reasonable to assume that the reader can figure out what the
code does; it is more useful to explain why.
This comment is redundant with the code and useless:
v = 8 # assign 8 to v
Good variable names can reduce the need for comments, but long names can make
complex expressions hard to read, so there is a trade-off.
Debugging
Three kinds of errors can occur in a program: syntax errors, runtime errors, and
semantic errors. It is useful to distinguish among them in order to track them down
more quickly:
Syntax error
“Syntax” refers to the structure of a program and the rules about that structure. If
there is a syntax error anywhere in your program, Python does not run the pro‐
gram. It displays an error message immediately.
Runtime error
If there are no syntax errors in your program, it can start running. But if some‐
thing goes wrong, Python displays an error message and stops. This type of error
is called a runtime error. It is also called an exception because it indicates that
something exceptional has happened.
Semantic error
The third type of error is “semantic,” which means related to meaning. If there is
a semantic error in your program, it runs without generating error messages, but
it does not do what you intended. Identifying semantic errors can be tricky
because it requires you to work backward by looking at the output of the pro‐
gram and trying to figure out what it is doing.
million! = 1000000
If you use an operator with a type it doesn’t support, that’s a runtime error:
'126' / 3
Finally, here’s an example of a semantic error. Suppose we want to compute the aver‐
age of 1 and 3, but we forget about the order of operations and write this:
1 + 3 / 2
2.5
When this expression is evaluated, it does not produce an error message, so there is
no syntax error or runtime error. But the result is not the average of 1 and 3, so the
program is not correct. This is a semantic error because the program runs but it
doesn’t do what’s intended.
Glossary
variable: A name that refers to a value.
assignment statement: A statement that assigns a value to a variable.
state diagram: A graphical representation of a set of variables and the values they
refer to.
keyword: A special word used to specify the structure of a program.
import statement: A statement that reads a module file and creates a module object.
module: A file that contains Python code, including function definitions and some‐
times other statements.
dot operator: The operator, ., used to access a function in another module by speci‐
fying the module name followed by a dot and the function name.
statement: One or more lines of code that represent a command or action.
evaluate: Perform the operations in an expression in order to compute a value.
Glossary | 23
execute: Run a statement and do what it says.
argument: A value provided to a function when the function is called. Each argu‐
ment is assigned to the corresponding parameter in the function.
comment: Text included in a program that provides information about the program
but has no effect on its execution.
runtime error: An error that causes a program to display an error message and exit.
exception: An error that is detected while the program is running.
semantic error: An error that causes a program to do the wrong thing, but not to
display an error message.
Exercises
Ask a Virtual Assistant
Again, I encourage you to use a virtual assistant to learn more about any of the topics
in this chapter.
If you are curious about any of keywords I listed, you could ask “Why is class a key‐
word?” or “Why can’t variable names be keywords?”
You might have noticed that int, float, and str are not Python keywords. They are
variables that represent types, and they can be used as functions. So it is legal to have
a variable or function with one of those names, but it is strongly discouraged. Ask an
assistant “Why is it bad to use int, float, and string as variable names?”
Also ask, “What are the built-in functions in Python?” If you are curious about any of
them, ask for more information.
In this chapter we imported the math module and used some of the variables and
functions it provides. Ask an assistant, “What variables and functions are in the math
module?” and “Other than math, what modules are considered core Python?”
Exercise
Repeating my advice from the previous chapter, whenever you learn a new feature,
you should make errors on purpose to see what goes wrong.
Exercise
Practice using the Python interpreter as a calculator:
4
Part 1. The volume of a sphere with radius r is 3 πr3. What is the volume of a sphere
with radius 5? Start with a variable named radius and then assign the result to a vari‐
able named volume. Display the result. Add comments to indicate that radius is in
centimeters and volume is in cubic centimeters.
Part 2. A rule of trigonometry says that for any value of x, cos x 2 + sin x 2 = 1.
Let’s see if it’s true for a specific value of x like 42.
Create a variable named x with this value. Then use math.cos and math.sin to com‐
pute the sine and cosine of x, and the sum of their squares.
The result should be close to 1. It might not be exactly 1 because floating-point arith‐
metic is not exact—it is only approximately correct.
Part 3. In addition to pi, the other variable defined in the math module is e, which
represents the base of the natural logarithm, written in math notation as e. If you are
not familiar with this value, ask a virtual assistant “What is math.e?” Now let’s com‐
pute e2 three ways:
You might notice that the last result is slightly different from the other two. See if you
can find out which is correct.
Exercises | 25
CHAPTER 3
Functions
In the previous chapter we used several functions provided by Python, like int and
float, and a few provided by the math module, like sqrt and pow. In this chapter, you
will learn how to create your own functions and run them. And we’ll see how one
function can call another. As examples, we’ll display lyrics from Monty Python songs.
These silly examples demonstrate an important feature—the ability to write your own
functions is the foundation of programming.
This chapter also introduces a new statement, the for loop, which is used to repeat a
computation.
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def is a keyword that indicates that this is a function definition. The name of the
function is print_lyrics. Anything that’s a legal variable name is also a legal func‐
tion name.
The empty parentheses after the name indicate that this function doesn’t take any
arguments.
The first line of the function definition is called the header—the rest is called the
body. The header has to end with a colon and the body has to be indented. By con‐
vention, indentation is always four spaces. The body of this function is two print
27
statements; in general, the body of a function can contain any number of statements
of any kind.
Defining a function creates a function object, which we can display like this:
print_lyrics
<function __main__.print_lyrics()>
print_lyrics()
When the function runs, it executes the statements in the body, which display the first
two lines of “The Lumberjack Song.”
Parameters
Some of the functions we have seen require arguments; for example, when you call
abs you pass a number as an argument. Some functions take more than one argu‐
ment; for example, math.pow takes two, the base and the exponent.
Here is a definition for a function that takes an argument:
def print_twice(string):
print(string)
print(string)
The variable name in parentheses is a parameter. When the function is called, the
value of the argument is assigned to the parameter. For example, we can call
print_twice like this:
Dennis Moore,
Dennis Moore,
28 | Chapter 3: Functions
Running this function has the same effect as assigning the argument to the parameter
and then executing the body of the function, like this:
Dennis Moore,
Dennis Moore,
Dennis Moore,
Dennis Moore,
In this example, the value of line gets assigned to the parameter string.
Calling Functions
Once you have defined a function, you can use it inside another function. To demon‐
strate, we’ll write functions that print the lyrics of “The Spam Song”:
Spam, Spam, Spam, Spam,
Spam, Spam, Spam, Spam,
Spam, Spam,
(Lovely Spam, Wonderful Spam!)
Spam, Spam,
We’ll start with the following function, which takes two parameters:
We can use this function to print the first line of the song, like this:
Calling Functions | 29
To display the first two lines, we can define a new function that uses repeat:
def first_two_lines():
repeat(spam, 4)
repeat(spam, 4)
first_two_lines()
To display the last three lines, we can define another function, which also uses
repeat:
def last_three_lines():
repeat(spam, 2)
print('(Lovely Spam, Wonderful Spam!)')
repeat(spam, 2)
last_three_lines()
Spam, Spam,
(Lovely Spam, Wonderful Spam!)
Spam, Spam,
Finally, we can bring it all together with one function that prints the whole verse:
def print_verse():
first_two_lines()
last_three_lines()
print_verse()
When we run print_verse, it calls first_two_lines, which calls repeat, which calls
print. That’s a lot of functions.
Of course, we could have done the same thing with fewer functions, but the point of
this example is to show how functions can work together.
30 | Chapter 3: Functions
Repetition
If we want to display more than one verse, we can use a for statement. Here’s a simple
example:
for i in range(2):
print(i)
0
1
The first line is a header that ends with a colon. The second line is the body, which
has to be indented.
The first line starts with the keyword for, a new variable named i, and another key‐
word, in. It uses the range function to create a sequence of two values, which are 0
and 1. In Python, when we start counting, we usually start from 0.
When the for statement runs, it assigns the first value from range to i and then runs
the print function in the body, which displays 0.
When it gets to the end of the body, it loops back around to the header, which is why
this statement is called a loop. The second time through the loop, it assigns the next
value from range to i, and displays it. Then, because that’s the last value from range,
the loop ends.
Here’s how we can use a for loop to print two verses of the song:
for i in range(2):
print("Verse", i)
print_verse()
print()
Verse 0
Spam, Spam, Spam, Spam,
Spam, Spam, Spam, Spam,
Spam, Spam,
(Lovely Spam, Wonderful Spam!)
Spam, Spam,
Verse 1
Spam, Spam, Spam, Spam,
Spam, Spam, Spam, Spam,
Spam, Spam,
(Lovely Spam, Wonderful Spam!)
Spam, Spam,
Repetition | 31
You can put a for loop inside a function. For example, print_n_verses takes a
parameter named n, which has to be an integer, and displays the given number of
verses:
def print_n_verses(n):
for i in range(n):
print_verse()
print()
In this example, we don’t use i in the body of the loop, but there has to be a variable
name in the header anyway.
When cat_twice runs, it creates a local variable named cat, which is destroyed when
the function ends. If we try to display it, we get a NameError:
print(cat)
32 | Chapter 3: Functions
CHAPTER 5
Conditionals and Recursion
The main topic of this chapter is the if statement, which executes different code
depending on the state of the program. With the if statement we’ll be able to explore
one of the most powerful ideas in computing, recursion.
But we’ll start with three new features: the modulus operator, boolean expressions,
and logical operators.
minutes = 105
minutes / 60
1.75
But we don’t normally write hours with decimal points. Floor division returns the
integer number of hours, rounding down:
minutes = 105
hours = minutes // 60
hours
55
To get the remainder, you could subtract off one hour, in minutes:
45
Or you could use the modulus operator, %, which divides two numbers and returns
the remainder:
remainder = minutes % 60
remainder
45
The modulus operator is more useful than it might seem. For example, it can check
whether one number is divisible by another: if x % y is zero, then x is divisible by y.
Also, it can extract the rightmost digit or digits from a number. For example, x % 10
yields the rightmost digit of x (in base 10). Similarly, x % 100 yields the last two
digits.
Finally, the modulus operator can do “clock arithmetic.” For example, if an event
starts at 11 A.M. and lasts three hours, we can use the modulus operator to figure out
what time it ends:
start = 11
duration = 3
end = (start + duration) % 12
end
a = 25 // 10
b = 25 % 10
a, b
(2, 5)
Boolean Expressions
A boolean expression is an expression that is either true or false. For example, the
following expressions use the equals operator, ==, which compares two values and
produces True if they are equal and False otherwise:
True
5 == 7
False
A common error is to use a single equals sign (=) instead of a double equals sign (==).
Remember that = assigns a value to a variable and == compares two values:
x = 5
y = 7
x == y
False
True and False are special values that belong to the type bool; they are not strings:
type(True)
bool
type(False)
bool
x != y # x is not equal to y
True
False
True
Boolean Expressions | 57
x >= y # x is greater than or equal to y
False
True
Logical Operators
To combine boolean values into expressions, we can use logical operators. The most
common are and, or, and not. The meaning of these operators is similar to their
meaning in English. For example, the value of the following expression is True only if
x is greater than 0 and less than 10:
True
The following expression is True if either or both of the conditions is true, that is, if
the number is divisible by 2 or 3:
x % 2 == 0 or x % 3 == 0
False
Finally, the not operator negates a boolean expression, so the following expression is
True if x > y is False:
not x > y
True
42 and True
True
This flexibility can be useful, but there are some subtleties to it that can be confusing.
You might want to avoid it.
if x > 0:
print('x is positive')
x is positive
if x < 0:
pass # TODO: need to handle negative values!
The word TODO in a comment is a conventional reminder that there’s something you
need to do later.
if x % 2 == 0:
print('x is even')
else:
print('x is odd')
x is odd
If the condition is true, the first indented statement runs; otherwise, the second
indented statement runs.
Chained Conditionals
Sometimes there are more than two possibilities and we need more than two
branches. One way to express a computation like that is a chained conditional, which
includes an elif clause:
if x < y:
print('x is less than y')
elif x > y:
print('x is greater than y')
else:
print('x and y are equal')
x is less than y
elif is an abbreviation of “else if.” There is no limit on the number of elif clauses. If
there is an else clause, it has to be at the end, but there doesn’t have to be one.
Each condition is checked in order. If the first is false, the next is checked, and so on.
If one of them is true, the corresponding branch runs and the if statement ends.
Even if more than one condition is true, only the first true branch runs.
Nested Conditionals
One conditional can also be nested within another. We could have written the exam‐
ple in the previous section like this:
if x == y:
print('x and y are equal')
else:
if x < y:
print('x is less than y')
else:
print('x is greater than y')
x is less than y
if 0 < x:
if x < 10:
print('x is a positive single-digit number.')
The print statement runs only if we make it past both conditionals, so we get the
same effect with the and operator:
Recursion
It is legal for a function to call itself. It may not be obvious why that is a good thing,
but it turns out to be one of the most magical things a program can do. Here’s an
example:
def countdown(n):
if n <= 0:
print('Blastoff!')
else:
print(n)
countdown(n-1)
Recursion | 61
If a program exceeds the limit, it causes a runtime error:
recurse()
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
Cell In[41], line 1
----> 1 recurse()
The traceback indicates that there were almost three thousand frames on the stack
when the error occurred.
If you encounter an infinite recursion by accident, review your function to confirm
that there is a base case that does not make a recursive call. And if there is a base case,
check whether you are guaranteed to reach it.
Keyboard Input
The programs we have written so far accept no input from the user. They just do the
same thing every time.
Python provides a built-in function called input that stops the program and waits for
the user to type something. When the user presses Return or Enter the program
resumes, and input returns what the user typed as a string:
text = input()
The sequence \n at the end of the prompt represents a newline, which is a special
character that causes a line break—that way the user’s input appears below the
prompt.
If you expect the user to type an integer, you can use the int function to convert the
return value to int:
But if they type something that’s not an integer, you’ll get a runtime error.
int(speed)
ValueError: invalid literal for int() with base 10: 'What do you mean:
an African or European swallow?'
Debugging
When a syntax or runtime error occurs, the error message contains a lot of informa‐
tion, but it can be overwhelming. The most useful parts are usually:
Debugging | 65
Syntax errors are usually easy to find, but there are a few gotchas. Errors related to
spaces and tabs can be tricky because they are invisible and we are used to ignoring
them:
x = 5
y = 6
In this example, the problem is that the second line is indented by one space. But the
error message points to y, which is misleading. Error messages indicate where the
problem was discovered, but the actual error might be earlier in the code.
The same is true of runtime errors. For example, suppose you are trying to convert a
ratio to decibels, like this:
import math
numerator = 9
denominator = 10
ratio = numerator // denominator
decibels = 10 * math.log10(ratio)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[52], line 5
3 denominator = 10
4 ratio = numerator // denominator
----> 5 decibels = 10 * math.log10(ratio)
The error message indicates line 5, but there is nothing wrong with that line. The
problem is in line 4, which uses floor division instead of floating-point division—as a
result, the value of ratio is 0. When we call math.log10, we get a ValueError with
the message math domain error, because 0 is not in the “domain” of valid arguments
for math.log10, because the logarithm of 0 is undefined.
In general, you should take the time to read error messages carefully, but don’t
assume that everything they say is correct.
Glossary
recursion: The process of calling the function that is currently executing.
modulus operator: An operator, %, that works on integers and returns the remainder
when one number is divided by another.
5.0
d = distance(1, 2, 4, 6)
The print statements we wrote are useful for debugging, but once the function is
working, we can remove them. Code like that is called scaffolding because it is help‐
ful for building the program but is not part of the final product. This example dem‐
onstrates incremental development. The key aspects of this process are:
1. Start with a working program, make small changes, and test after every change.
2. Use variables to hold intermediate values so you can display and check them.
3. Once the program is working, remove the scaffolding.
At any point, if there is an error, you should have a good idea where it is. Incremental
development can save you a lot of debugging time.
Boolean Functions
Functions can return the boolean values True and False, which is often convenient
for encapsulating a complex test in a function. For example, is_divisible checks
whether x is divisible by y with no remainder:
is_divisible(6, 4)
False
is_divisible(6, 3)
True
if is_divisible(6, 2):
print('divisible')
divisible
if is_divisible(6, 2) == True:
print('divisible')
divisible
If you saw that definition in the dictionary, you might be annoyed. On the other
hand, if you looked up the definition of the factorial function, denoted with the sym‐
bol !, you might get something like this:
0! = 1
n! = n n − 1 !
This definition says that the factorial of 0 is 1, and the factorial of any other value, n,
is n multiplied by the factorial of n − 1.
In 1939, Ernest Vincent Wright published a 50,000-word novel called Gadsby that
does not contain the letter “e.” Since “e” is the most common letter in English, writing
even a few words without using it is difficult. To get a sense of how difficult, in this
chapter we’ll compute the fraction of English words have at least one “e.”
For that, we’ll use for statements to loop through the letters in a string and the words
in a file, and we’ll update variables in a loop to count the number of words that con‐
tain an “e.” We’ll use the in operator to check whether a letter appears in a word, and
you’ll learn a programming pattern called a “linear search.”
As an exercise, you’ll use these tools to solve a word puzzle called “Spelling Bee.”
for i in range(3):
print(i, end=' ')
0 1 2
This version uses the keyword argument end, so the print function puts a space after
each number rather than a newline.
91
We can also use a for loop to display the letters in a string:
G a d s b y
Notice that I changed the name of the variable from i to letter, which provides
more information about the value it refers to. The variable defined in a for loop is
called the loop variable.
Now that we can loop through the letters in a word, we can check whether it contains
the letter “e”:
def has_e():
for letter in "Gadsby":
if letter == 'E' or letter == 'e':
print('This word has an "e"')
And let’s make it a pure function that returns True if the word contains an “e” and
False otherwise:
def has_e():
for letter in "Gadsby":
if letter == 'E' or letter == 'e':
return True
return False
def has_e(word):
for letter in word:
if letter == 'E' or letter == 'e':
return True
return False
has_e('Gadsby')
False
has_e('Emma')
True
file_object = open('words.txt')
The file object provides a function called readline, which reads characters from the
file until it gets to a newline and returns the result as a string:
file_object.readline()
'aa\n'
Notice that the syntax for calling readline is different from functions we’ve seen so
far. That’s because it is a method, which is a function associated with an object. In this
case readline is associated with the file object, so we call it using the name of the
object, the dot operator, and the name of the method.
The first word in the list is “aa,” which is a type of lava. The sequence \n represents
the newline character that separates this word from the next.
The file object keeps track of where it is in the file, so if you call readline again, you
get the next word:
line = file_object.readline()
line
'aah\n'
word = line.strip()
word
'aah'
Now that we can read the word list, the next step is to count the words. For that, we
will need the ability to update variables.
Updating Variables
As you may have discovered, it is legal to make more than one assignment to the
same variable. A new assignment makes an existing variable refer to a new value (and
stop referring to the old value).
For example, here is an initial assignment that creates a variable:
x = 5
x
x = 7
x
The following figure shows what these assignments look like in a state diagram:
x = x + 1
x
This statement means “get the current value of x, add one, and assign the result back
to x.”
If you try to update a variable that doesn’t exist, you get an error, because Python
evaluates the expression on the right before it assigns a value to the variable on the
left:
y = y + 1
Before you can update a variable, you have to initialize it, usually with a simple
assignment:
y = 0
y = y + 1
y
Increasing the value of a variable is called an increment; decreasing the value is called
a decrement.
total = 0
total
113783
A variable like this, used to count the number of times something happens, is called a
counter.
We can add a second counter to the program to keep track of the number of words
that contain an “e”:
total = 0
count = 0
count
76162
As a percentage of total, about two-thirds of the words use the letter “e”:
66.93618554617122
So you can understand why it’s difficult to craft a book without using any such words.
The in Operator
The version of has_e we wrote in this chapter is more complicated than it needs to
be. Python provides an operator, in, that checks whether a character appears in a
string:
word = 'Gadsby'
'e' in word
False
def has_e(word):
if 'E' in word or 'e' in word:
return True
else:
return False
And because the conditional of the if statement has a boolean value, we can elimi‐
nate the if statement and return the boolean directly:
def has_e(word):
return 'E' in word or 'e' in word
We can simplify this function even more using the method lower, which converts the
letters in a string to lowercase. Here’s an example:
word.lower()
'gadsby'
lower makes a new string—it does not modify the existing string—so the value of
word is unchanged:
word
'Gadsby'
def has_e(word):
return 'e' in word.lower()
has_e('Gadsby')
False
has_e('Emma')
True
The in Operator | 97
Search
Based on this simpler version of has_e, let’s write a more general function called
uses_any that takes a second parameter that is a string of letters. It returns True if the
word uses any of the letters, and False otherwise:
uses_any('banana', 'aeiou')
True
uses_any('apple', 'xyz')
False
uses_only converts word and letters to lowercase, so it works with any combination
of cases:
uses_any('Banana', 'AEIOU')
True
The structure of uses_any is similar to has_e. It loops through the letters in word and
checks them one at a time. If it finds one that appears in letters, it returns True
immediately. If it gets all the way through the loop without finding any, it returns
False.
This pattern is called a linear search. In the exercises at the end of this chapter, you’ll
write more functions that use this pattern.
def getGrades(fname):
try:
gradesFile = open(fname, 'r') #open file for reading
except IOError:
raise ValueError('getGrades could not open ' + fname)
grades = []
for line in gradesFile:
try:
grades.append(float(line))
except:
raise ValueError('Unable to convert line to float')
return grades
try:
grades = getGrades('quiz1grades.txt')
grades.sort()
median = grades[len(grades)//2]
print('Median grade is', median)
except ValueError as errorMsg:
print('Whoops.', errorMsg)
7.3 Assertions
The Python assert statement provides programmers with a simple way to con-
firm that the state of a computation is as expected. An assert statement can take
one of two forms:
assert Boolean expression
or
assert Boolean expression, argument
When an assert statement is encountered, the Boolean expression is evaluat-
ed. If it evaluates to True, execution proceeds on its merry way. If it evaluates to
False, an AssertionError exception is raised.
Assertions are a useful defensive programming tool. They can be used to
confirm that the arguments to a function are of appropriate types. They are also a
useful debugging tool. The can be used, for example, to confirm that intermedi-
ate values have the expected values or that a function returns an acceptable value.
9 A SIMPLISTIC INTRODUCTION TO ALGORITHMIC
COMPLEXITY
The most important thing to think about when designing and implementing a
program is that it should produce results that can be relied upon. We want our
bank balances to be calculated correctly. We want the fuel injectors in our auto-
mobiles to inject appropriate amounts of fuel. We would prefer that neither air-
planes nor operating systems crash.
Sometimes performance is an important aspect of correctness. This is most
obvious for programs that need to run in real time. A program that warns air-
planes of potential obstructions needs to issue the warning before the obstruc-
tions are encountered. Performance can also affect the utility of many non-real-
time programs. The number of transactions completed per minute is an im-
portant metric when evaluating the utility of database systems. Users care about
the time required to start an application on their phone. Biologists care about
how long their phylogenetic inference calculations take.
Writing efficient programs is not easy. The most straightforward solution is
often not the most efficient. Computationally efficient algorithms often employ
subtle tricks that can make them difficult to understand. Consequently, pro-
grammers often increase the conceptual complexity of a program in an effort to
reduce its computational complexity. To do this in a sensible way, we need to un-
derstand how to go about estimating the computational complexity of a program.
That is the topic of this chapter.
We could run the program on some input and time it. But that wouldn’t be par-
ticularly informative because the result would depend upon
• the speed of the computer on which it is run,
• the efficiency of the Python implementation on that machine, and
• the value of the input.
We get around the first two issues by using a more abstract measure of time.
Instead of measuring time in milliseconds, we measure time in terms of the
number of basic steps executed by the program.
For simplicity, we will use a random access machine as our model of compu-
tation. In a random access machine, steps are executed sequentially, one at a
time.53 A step is an operation that takes a fixed amount of time, such as binding a
variable to an object, making a comparison, executing an arithmetic operation,
or accessing an object in memory.
Now that we have a more abstract way to think about the meaning of time,
we turn to the question of dependence on the value of the input. We deal with
that by moving away from expressing time complexity as a single number and
instead relating it to the sizes of the inputs. This allows us to compare the effi-
ciency of two algorithms by talking about how the running time of each grows
with respect to the sizes of the inputs.
Of course, the actual running time of an algorithm depends not only upon
the sizes of the inputs but also upon their values. Consider, for example, the line-
ar search algorithm implemented by
def linearSearch(L, x):
for e in L:
if e == x:
return True
return False
Suppose that L is a list containing a million elements, and consider the call
linearSearch(L, 3). If the first element in L is 3, linearSearch will return True al-
most immediately. On the other hand, if 3 is not in L, linearSearch will have to
examine all one million elements before returning False.
In general, there are three broad cases to think about:
• The best-case running time is the running time of the algorithm when the in-
puts are as favorable as possible. I.e., the best-case running time is the mini-
53A more accurate model for today’s computers might be a parallel random access machine.
However, that adds considerable complexity to the algorithmic analysis, and often doesn’t make an
important qualitative difference in the answer.
CHAPTER 9. A SIMPLISTIC INTRODUCTION TO ALGORITHMIC COMPLEXITY 137
mum running time over all the possible inputs of a given size. For
linearSearch, the best-case running time is independent of the size of L.
• Similarly, the worst-case running time is the maximum running time over all
the possible inputs of a given size. For linearSearch, the worst-case running
time is linear in the size of L.
• By analogy with the definitions of the best-case and worst-case running time,
the average-case (also called expected-case) running time is the average run-
ning time over all possible inputs of a given size. Alternatively, if one has some
a priori information about the distribution of input values (e.g., that 90% of
the time x is in L), one can take that into account.
People usually focus on the worst case. All engineers share a common article
of faith, Murphy’s Law: If something can go wrong, it will go wrong. The worst-
case provides an upper bound on the running time. This is critical in situations
where there is a time constraint on how long a computation can take. It is not
good enough to know that “most of the time” the air traffic control system warns
of impending collisions before they occur.
Let’s look at the worst-case running time of an iterative implementation of
the factorial function:
def fact(n):
"""Assumes n is a natural number
Returns n!"""
answer = 1
while n > 1:
answer *= n
n -= 1
return answer
The number of steps required to run this program is something like 2 (1 for
the initial assignment statement and 1 for the return) + 5n (counting 1 step for
the test in the while, 2 steps for the first assignment statement in the while loop,
and 2 steps for the second assignment statement in the loop). So, for example, if n
is 1000, the function will execute roughly 5002 steps.
It should be immediately obvious that as n gets large, worrying about the dif-
ference between 5n and 5n+2 is kind of silly. For this reason, we typically ignore
additive constants when reasoning about running time. Multiplicative constants
are more problematical. Should we care whether the computation takes 1000
steps or 5000 steps? Multiplicative factors can be important. Whether a search
engine takes a half second or 2.5 seconds to service a query can be the difference
between whether people use that search engine or go to a competitor.
138 INTRODUCTION TO COMPUTATION AND PROGRAMMING USING PYTHON
On the other hand, when one is comparing two different algorithms, it is of-
ten the case that even multiplicative constants are irrelevant. Recall that in Chap-
ter 3 we looked at two algorithms, exhaustive enumeration and bisection search,
for finding an approximation to the square root of a floating point number.
Functions based on these algorithms are shown in Figure 9.1 and Figure 9.2.
Checkpoint
1.18 A CPU understands instructions that are written only in what language?
1.19 A program has to be copied into what type of memory each time the CPU
executes it?
1.20 When a CPU executes the instructions in a program, it is engaged in what process?
1.21 What is assembly language?
1.22 What type of programming language allows you to create powerful and complex
programs without knowing how the CPU works?
1.23 Each language has a set of rules that must be strictly followed when writing a
program. What is this set of rules called?
1.24 What do you call a program that translates a high-level language program into a
separate machine language program?
1.25 What do you call a program that both translates and executes the instructions in
a high-level language program?
1.26 What type of mistake is usually caused by a misspelled keyword, a missing
punctuation character, or the incorrect use of an operator?
CONCEPT: The Python interpreter can run Python programs that are saved in files
or interactively execute Python statements that are typed at the keyboard.
Python comes with a program named IDLE that simplifies the process of
writing, executing, and testing programs.
Installing Python
Before you can try any of the programs shown in this book, or write any programs of your
own, you need to make sure that Python is installed on your computer and properly con-
figured. If you are working in a computer lab, this has probably been done already. If you
are using your own computer, you can follow the instructions in Appendix A to download
and install Python.
Interactive Mode
Once Python has been installed and set up on your system, you start the interpreter in
interactive mode by going to the operating system’s command line and typing the follow-
ing command:
python
If you are using Windows, you can alternatively type python in the Windows search box.
In the search results, you will see a program named something like Python 3.5. (The “3.5”
is the version of Python that is installed. At the time this is being written, Python 3.5 is
the latest version.) Clicking this item will start the Python interpreter in interactive mode.
When the Python interpreter starts in interactive mode, you will see something like the fol-
lowing displayed in a console window:
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 19:29:22)
[MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license"
for more information.
>>>
The >>> that you see is a prompt that indicates the interpreter is waiting for you to type
a Python statement. Let’s try it out. One of the simplest things that you can do in Python
is print a message on the screen. For example, the following statement prints the message
Python programming is fun! on the screen:
print('Python programming is fun!')
You can think of this as a command that you are sending to the Python interpreter. If
you type the statement exactly as it is shown, the message Python programming is fun! is
printed on the screen. Here is an example of how you type this statement at the interpreter’s
prompt:
>>> print('Python programming is fun!') Enter
After typing the statement, you press the Enter key, and the Python interpreter executes the
statement, as shown here:
>>> print('Python programming is fun!') Enter
Python programming is fun!
>>>
22 Chapter 1 Introduction to Computers and Programming
After the message is displayed, the >>> prompt appears again, indicating the interpreter is
waiting for you to enter another statement. Let’s look at another example. In the following
sample session, we have entered two statements:
>>> print('To be or not to be') Enter
To be or not to be
>>> print('That is the question.') Enter
That is the question.
>>>
If you incorrectly type a statement in interactive mode, the interpreter will display an error
message. This will make interactive mode useful to you while you learn Python. As you
learn new parts of the Python language, you can try them out in interactive mode and get
immediate feedback from the interpreter.
To quit the Python interpreter in interactive mode on a Windows computer, press Ctrl-Z
(pressing both keys together) followed by Enter. On a Mac, Linux, or UNIX computer,
press Ctrl-D.
NOTE: In Chapter 2, we will discuss the details of statements like the ones previously
shown. If you want to try them now in interactive mode, make sure you type them exactly
as shown.
To write the program you would use a simple text editor like Notepad (which is installed
on all Windows computers) to create a file containing the following statements:
print('Nudge nudge')
print('Wink wink')
print('Know what I mean?')
NOTE : It is possible to use a word processor to create a Python program, but you must
be sure to save the program as a plain text file. Otherwise, the Python interpreter will
not be able to read its contents.
1.5 Using Python 23
When you save a Python program, you give it a name that ends with the .py extension,
which identifies it as a Python program. For example, you might save the program previ-
ously shown with the name test.py. To run the program, you would go to the directory
in which the file is saved and type the following command at the operating system com-
mand line:
python test.py
This starts the Python interpreter in script mode and causes it to execute the statements in
the file test.py. When the program finishes executing, the Python interpreter exits.
parts of a program are displayed in their own distinct colors. This helps make programs
easier to read. In IDLE, you can write programs, save them to disk, and execute them.
Appendix B provides a quick introduction to IDLE and leads you through the process
of creating, saving, and executing a Python program.
NOTE: Although IDLE is installed with Python, there are several other Python IDEs
available. Your instructor might prefer that you use a specific one in class.
Review Questions
Multiple Choice
1. A(n) __________ is a set of instructions that a computer follows to perform a task.
a. compiler
b. program
c. interpreter
d. programming language
2. The physical devices that a computer is made of are referred to as __________.
a. hardware
b. software
c. the operating system
d. tools
3. The part of a computer that runs programs is called __________.
a. RAM
b. secondary storage
c. main memory
e. the CPU
4. Today, CPUs are small chips known as __________.
a. ENIACs
b. microprocessors
c. memory chips
d. operating systems
5. The computer stores a program while the program is running, as well as the data that
the program is working with, in __________.
a. secondary storage
b. the CPU
c. main memory
d. the microprocessor
6. This is a volatile type of memory that is used only for temporary storage while a pro-
gram is running.
a. RAM
b. secondary storage
c. the disk drive
d. the USB drive
CHAPTER
TOPICS
7.1 Sequences 7.6 Copying Lists
7.2 Introduction to Lists 7.7 Processing Lists
7.3 List Slicing 7.8 List Comprehensions
7.4 Finding Items in Lists with the 7.9 Two-Dimensional Lists
in Operator 7.10 Tuples
7.5 List Methods and Useful Built-in 7.11 Plotting List Data with the
Functions matplotlib Package
7.1 Sequences
CONCEPT: A sequence is an object that holds multiple items of data, stored one
after the other. You can perform operations on a sequence to examine
and manipulate the items stored in it.
A sequence is an object that contains multiple items of data. The items that are in a sequence
are stored one after the other. Python provides various ways to perform operations on the
items that are stored in a sequence.
There are several different types of sequence objects in Python. In this chapter, we will
look at two of the fundamental sequence types: lists and tuples. Both lists and tuples are
sequences that can hold various types of data. The difference between lists and tuples is
simple: a list is mutable, which means that a program can change its contents, but a tuple
is immutable, which means that once it is created, its contents cannot be changed. We will
explore some of the operations that you may perform on these sequences, including ways
to access and manipulate their contents.
CONCEPT: A list is an object that contains multiple data items. Lists are mutable,
which means that their contents can be changed during a program’s
execution. Lists are dynamic data structures, meaning that items may be
added to them or removed from them. You can use indexing, slicing, and
various methods to work with lists in a program.
361
362 Chapter 7 Lists and Tuples
A list is an object that contains multiple data items. Each item that is stored in a list is called
an element. Here is a statement that creates a list of integers:
even_numbers = [2, 4, 6, 8, 10]
The items that are enclosed in brackets and separated by commas are the list elements.
After this statement executes, the variable even_numbers will reference the list, as shown
in Figure 7-1.
even_numbers 2 4 6 8 10
This statement creates a list of five strings. After the statement executes, the name variable
will reference the list as shown in Figure 7-2.
A list can hold items of different types, as shown in the following example:
info = ['Alicia', 27, 1550.87]
This statement creates a list containing a string, an integer, and a floating-point number.
After the statement executes, the info variable will reference the list as shown in Figure 7-3.
You can use the print function to display an entire list, as shown here:
numbers = [5, 10, 15, 20]
print(numbers)
In this example, the print function will display the elements of the list like this:
[5, 10, 15, 20]
Python also has a built-in list() function that can convert certain types of objects to lists.
For example, recall from Chapter 4 that the range function returns an iterable, which is an
object that holds a series of values that can be iterated over. You can use a statement such
as the following to convert the range function’s iterable object to a list:
numbers = list(range(5))
7.2 Introduction to Lists 363
Recall from Chapter 4 that when you pass three arguments to the range function, the first
argument is the starting value, the second argument is the ending limit, and the third argu-
ment is the step value. This statement will assign the list [1, 3, 5, 7, 9] to the numbers
variable.
In the general format, list is a list, and n is the number of copies to make. The following
interactive session demonstrates:
1 >>> numbers = [0] * 5 Enter
2 >>> print(numbers) Enter
3 [0, 0, 0, 0, 0]
4 >>>
NOTE: Most programming languages allow you to create sequence structures known
as arrays, which are similar to lists, but are much more limited in their capabilities.
You cannot create traditional arrays in Python because lists serve the same purpose and
provide many more built-in capabilities.
364 Chapter 7 Lists and Tuples
In the general format, variable is the name of a variable, and list is the name of a list.
Each time the loop iterates, variable will reference a copy of an element in list, begin-
ning with the first element. We say that the loop iterates over the elements in the list. Here
is an example:
numbers = [1, 2, 3, 4]
for num in numbers:
print(num)
The numbers variable references a list with four elements, so this loop will iterate four
times. The first time the loop iterates, the num variable will reference the value 1, the sec-
ond time the loop iterates, the num variable will reference the value 2, and so forth. This is
illustrated in Figure 7-4. When the code executes, it will display the following:
1
1st Iteration for num in numbers: 2nd Iteration for num in numbers:
print(num) print(num)
numbers 1, 2, 3, 4 numbers 1, 2, 3, 4
num 1 num 2
3rd Iteration for num in numbers: 4th Iteration for num in numbers:
print(num) print(num)
numbers 1, 2, 3, 4 numbers 1, 2, 3, 4
num 3 num 4
7.2 Introduction to Lists 365
Figure 7-4 illustrates how the num variable references a copy of an element from the num-
bers list as the loop iterates. It is important to realize that we cannot use the num variable
to change the contents of an element in the list. If we change the value that num references
in the loop, it has no effect on the list. To demonstrate, look at the following code:
1 numbers = [1, 2, 3, 4]
2 for num in numbers:
3 num = 99
4 print(numbers)
The statement in line 3 merely reassigns the num variable to the value 99 each time the loop
iterates. It has no effect on the list that is referenced by numbers. When this code executes,
the statement in line 4 will print:
[1, 2, 3, 4]
Indexing
Another way that you can access the individual elements in a list is with an index. Each
element in a list has an index that specifies its position in the list. Indexing starts at 0, so the
index of the first element is 0, the index of the second element is 1, and so forth. The index
of the last element in a list is 1 less than the number of elements in the list.
For example, the following statement creates a list with 4 elements:
my_list = [10, 20, 30, 40]
The indexes of the elements in this list are 0, 1, 2, and 3. We can print the elements of the
list with the following statement:
print(my_list[0], my_list[1], my_list[2], my_list[3])
You can also use negative indexes with lists to identify element positions relative to the end
of the list. The Python interpreter adds negative indexes to the length of the list to determine
the element position. The index −1 identifies the last element in a list, −2 identifies the next
to last element, and so forth. The following code shows an example:
my_list = [10, 20, 30, 40]
print(my_list[−1], my_list[−2], my_list[−3], my_list[−4])
An IndexError exception will be raised if you use an invalid index with a list. For example,
look at the following code:
# This code will cause an IndexError exception.
my_list = [10, 20, 30, 40]
366 Chapter 7 Lists and Tuples
index = 0
while index < 5:
print(my_list[index])
index += 1
The last time that this loop begins an iteration, the index variable will be assigned the
value 4, which is an invalid index for the list. As a result, the statement that calls the print
function will cause an IndexError exception to be raised.
The first statement assigns the list [10, 20, 30, 40] to the my_list variable. The second
statement calls the len function, passing the my_list variable as an argument.
The function returns the value 4, which is the number of elements in the list. This value is
assigned to the size variable.
The len function can be used to prevent an IndexError exception when iterating over a
list with a loop. Here is an example:
my_list = [10, 20, 30, 40]
index = 0
while index < len(my_list):
print(my_list[index])
index += 1
The expression range(len(names)) will give us the values 0, 1, 2, and 3. Because these
values are the valid indexes for the list, we can use the expression in a for loop, as shown
in the following code:
1 names = ['Jenny', 'Kelly', 'Chloe', 'Aubrey']
2 for index in range(len(names)):
3 print(names[index])
As the for loop iterates, the index variable will be assigned the values 0, 1, 2, and 3. The
code will display the following:
Jenny
Kelly
Chloe
Aubrey
7.2 Introduction to Lists 367
The statement in line 3 assigns 99 to numbers[0]. This changes the first value in the list to
99. When the statement in line 4 executes, it will display
[99, 2, 3, 4, 5]
When you use an indexing expression to assign a value to a list element, you must use a
valid index for an existing element or an IndexError exception will occur. For example,
look at the following code:
numbers = [1, 2, 3, 4, 5] # Create a list with 5 elements.
numbers[5] = 99 # This raises an exception!
The numbers list that is created in the first statement has five elements, with the indexes 0
through 4. The second statement will raise an IndexError exception because the numbers
list has no element at index 5.
If you want to use indexing expressions to fill a list with values, you have to create the list
first, as shown here:
1 # Create a list with 5 elements.
2 numbers = [0] * 5
3
4 # Fill the list with the value 99.
5 for index in range(len(numbers)):
6 numbers[index] = 99
The statement in line 2 creates a list with five elements, each element assigned the value 0.
The loop in lines 5 through 6 then steps through the list elements, assigning 99 to each one.
Program 7-1 shows an example of how user input can be assigned to the elements of a list.
This program gets sales amounts from the user and assigns them to a list.
5 def main():
6 # Create a list to hold the sales for each day.
7 sales = [0] * NUM_DAYS
8
9 print('Enter the sales for each day.')
10
11 # Get the sales for each day.
12 for index in range(len(sales)):
13 sales[index] = float(input(f'Day #{index + 1}: '))
14
15 # Display the values entered.
16 print('Here are the values you entered:')
17 for value in sales:
18 print(value)
19
20 # Call the main function.
21 if _ _name_ _ == '_ _main_ _':
22 main()
The statement in line 3 creates the variable NUM_DAYS, which is used as a constant for the
number of days. The statement in line 7 creates a list with five elements, with each element
assigned the value 0.
The loop in lines 12 through 13 iterates 5 times. The first time it iterates, index references
the value 0, so the statement in line 13 assigns the user’s input to sales[0]. The second
time the loop iterates, index references the value 1, so the statement in line 13 assigns the
user’s input to sales[1]. This continues until input values have been assigned to all the
elements in the list.
7.2 Introduction to Lists 369
Concatenating Lists
To concatenate means to join two things together. You can use the + operator to concat-
enate two lists. Here is an example:
list1 = [1, 2, 3, 4]
list2 = [5, 6, 7, 8]
list3 = list1 + list2
After this code executes, list1 and list2 remain unchanged, and list3 references the
following list:
[1, 2, 3, 4, 5, 6, 7, 8]
You can also use the += augmented assignment operator to concatenate one list to another.
Here is an example:
list1 = [1, 2, 3, 4]
list2 = [5, 6, 7, 8]
list1 += list2
The last statement appends list2 to list1. After this code executes, list2 remains
unchanged, but list1 references the following list:
[1, 2, 3, 4, 5, 6, 7, 8]
The following interactive mode session also demonstrates the += operator used for list
concatenation:
>>> girl_names = ['Joanne', 'Karen', 'Lori'] Enter
>>> girl_names += ['Jenny', 'Kelly'] Enter
>>> print(girl_names) Enter
['Joanne', 'Karen', 'Lori', 'Jenny', 'Kelly']
>>>
NOTE: Keep in mind that you can concatenate lists only with other lists. If you try to
concatenate a list with something that is not a list, an exception will be raised.
Checkpoint
7.1 What will the following code display?
numbers = [1, 2, 3, 4, 5]
numbers[2] = 99
print(numbers)
370 Chapter 7 Lists and Tuples
You have seen how indexing allows you to select a specific element in a sequence. Sometimes
you want to select more than one element from a sequence. In Python, you can write expres-
sions that select subsections of a sequence, known as slices.
A slice is a span of items that are taken from a sequence. When you take a slice from a list,
you get a span of elements from within the list. To get a slice of a list, you write an expres-
VideoNote
List Slicing sion in the following general format:
list_name[start : end]
In the general format, start is the index of the first element in the slice, and end is the
index marking the end of the slice. The expression returns a list containing a copy of
7.3 List Slicing 371
the elements from start up to (but not including) end. For example, suppose we create
the following list:
days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday']
The following statement uses a slicing expression to get the elements from indexes 2 up to,
but not including, 5:
mid_days = days[2:5]
After this statement executes, the mid_days variable references the following list:
['Tuesday', 'Wednesday', 'Thursday']
You can quickly use the interactive mode interpreter to see how slicing works. For example,
look at the following session. (We have added line numbers for easier reference.)
1 >>> numbers = [1, 2, 3, 4, 5] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5]
4 >>> print(numbers[1:3]) Enter
5 [2, 3]
6 >>>
If you leave out the start index in a slicing expression, Python uses 0 as the starting index.
The following interactive mode session shows an example:
1 >>> numbers = [1, 2, 3, 4, 5] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5]
4 >>> print(numbers[:3]) Enter
5 [1, 2, 3]
6 >>>
Notice line 4 sends the slice numbers[:3] as an argument to the print function. Because
the starting index was omitted, the slice contains the elements from index 0 up to 3.
If you leave out the end index in a slicing expression, Python uses the length of the list as
the end index. The following interactive mode session shows an example:
1 >>> numbers = [1, 2, 3, 4, 5] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5]
4 >>> print(numbers[2:]) Enter
5 [3, 4, 5]
6 >>>
372 Chapter 7 Lists and Tuples
Notice line 4 sends the slice numbers[2:] as an argument to the print function. Because
the ending index was omitted, the slice contains the elements from index 2 through the end
of the list.
If you leave out both the start and end index in a slicing expression, you get a copy of the
entire list. The following interactive mode session shows an example:
1 >>> numbers = [1, 2, 3, 4, 5] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5]
4 >>> print(numbers[:]) Enter
5 [1, 2, 3, 4, 5]
6 >>>
The slicing examples we have seen so far get slices of consecutive elements from lists. Slicing
expressions can also have step value, which can cause elements to be skipped in the list.
The following interactive mode session shows an example of a slicing expression with a
step value:
1 >>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4 >>> print(numbers[1:8:2]) Enter
5 [2, 4, 6, 8]
6 >>>
In the slicing expression in line 4, the third number inside the brackets is the step value. A
step value of 2, as used in this example, causes the slice to contain every second element
from the specified range in the list.
You can also use negative numbers as indexes in slicing expressions to reference positions
relative to the end of the list. Python adds a negative index to the length of a list to get
the position referenced by that index. The following interactive mode session shows an
example:
1 >>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Enter
2 >>> print(numbers) Enter
3 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4 >>> print(numbers[−5:]) Enter
5 [6, 7, 8, 9, 10]
6 >>>
NOTE: Invalid indexes do not cause slicing expressions to raise an exception. For
example:
• If the end index specifies a position beyond the end of the list, Python will use the
length of the list instead.
• If the start index specifies a position before the beginning of the list, Python will
use 0 instead.
• If the start index is greater than the end index, the slicing expression will return
an empty list.
7.4 Finding Items in Lists with the in Operator 373
Checkpoint
7.9 What will the following code display?
numbers = [1, 2, 3, 4, 5]
my_list = numbers[1:3]
print(my_list)
7.10 What will the following code display?
numbers = [1, 2, 3, 4, 5]
my_list = numbers[1:]
print(my_list)
7.11 What will the following code display?
numbers = [1, 2, 3, 4, 5]
my_list = numbers[:1]
print(my_list)
7.12 What will the following code display?
numbers = [1, 2, 3, 4, 5]
my_list = numbers[:]
print(my_list)
7.13 What will the following code display?
numbers = [1, 2, 3, 4, 5]
my_list = numbers[−3:]
print(my_list)
CONCEPT: You can search for an item in a list using the in operator.
In Python, you can use the in operator to determine whether an item is contained in a list.
Here is the general format of an expression written with the in operator to search for an
item in a list:
item in list
In the general format, item is the item for which you are searching, and list is a list. The
expression returns true if item is found in the list, or false otherwise. Program 7-2 shows
an example.
The program gets a product number from the user in line 9 and assigns it to the search
variable. The if statement in line 12 determines whether search is in the prod_nums list.
You can use the not in operator to determine whether an item is not in a list. Here is an
example:
if search not in prod_nums:
print(f'{search} was not found in the list.')
else:
print(f'{search} was found in the list.')
Checkpoint
7.14 What will the following code display?
names = ['Jim', 'Jill', 'John', 'Jasmine']
if 'Jasmine' not in names:
print('Cannot find Jasmine.')
else:
print("Jasmine's family:")
print(names)
7.5 List Methods and Useful Built-in Functions 375
CONCEPT: Lists have numerous methods that allow you to work with the elements
that they contain. Python also provides some built-in functions that are
useful for working with lists.
Lists have numerous methods that allow you to add elements, remove elements, change
the ordering of elements, and so forth. We will look at a few of these methods,1 which are
listed in Table 7-1.
1
We do not cover all of the list methods in this book. For a description of all of the list methods,
see the Python documentation at www.python.org.
376 Chapter 7 Lists and Tuples
7
8 # Create a variable to control the loop.
9 again = 'y'
10
11 # Add some names to the list.
12 while again == 'y':
13 # Get a name from the user.
14 name = input('Enter a name: ')
15
16 # Append the name to the list.
17 name_list.append(name)
18
19 # Add another one?
20 print('Do you want to add another name?')
21 again = input('y = yes, anything else = no: ')
22 print()
23
24 # Display the names that were entered.
25 print('Here are the names you entered.')
26
27 for name in name_list:
28 print(name)
29
30 # Call the main function.
31 if _ _name_ _ == '_ _main_ _':
32 main()
This statement creates an empty list (a list with no elements) and assigns it to the
name_list variable. Inside the loop, the append method is called to build the list. The first
time the method is called, the argument passed to it will become element 0. The second
time the method is called, the argument passed to it will become element 1. This continues
until the user exits the loop.
28 print(food)
29 except ValueError:
30 print('That item was not found in the list.')
31
32 # Call the main function.
33 if _ _name_ _ == '_ _main_ _':
34 main()
The elements of the food list are displayed in line 11, and in line 14, the user is asked which
item he or she wants to change. Line 18 calls the index method to get the index of the item.
Line 21 gets the new value from the user, and line 24 assigns the new value to the element
holding the old value.
16 print(names)
17
18 # Call the main function.
19 if _ _name_ _ == '_ _main_ _':
20 main()
Program Output
The list before the insert:
['James', 'Kathryn', 'Bill']
The list after the insert:
['Joe', 'James', 'Kathryn', 'Bill']
The max function accepts a sequence, such as a list, as an argument and returns the item
that has the highest value in the sequence. Here is an example:
my_list = [5, 4, 3, 2, 50, 40, 30]
print('The highest value is', max(my_list))
Checkpoint
7.15 What is the difference between calling a list’s remove method and using the del
statement to remove an element?
7.16 How do you find the lowest and highest values in a list?
382 Chapter 7 Lists and Tuples
CONCEPT: To make a copy of a list, you must copy the list’s elements.
Recall that in Python, assigning one variable to another variable simply makes both vari-
ables reference the same object in memory. For example, look at the following code:
# Create a list.
list1 = [1, 2, 3, 4]
# Assign the list to the list2 variable.
list2 = list1
After this code executes, both variables list1 and list2 will reference the same list in
memory. This is shown in Figure 7-5.
list1
1 2 3 4
list2
After this code executes, list1 and list2 will reference two separate but identical lists.
A simpler and more elegant way to accomplish the same task is to use the concatenation
operator, as shown here:
# Create a list with values.
list1 = [1, 2, 3, 4]
# Create a copy of list1.
list2 = [] + list1
The last statement in this code concatenates an empty list with list1 and assigns the
resulting list to list2. As a result, list1 and list2 will reference two separate but
identical lists.
In the Spotlight:
Using List Elements in a Math Expression
Megan owns a small neighborhood coffee shop, and she has six employees who work as
baristas (coffee bartenders). All of the employees have the same hourly pay rate. Megan has
asked you to design a program that will allow her to enter the number of hours worked by
each employee, then display the amounts of all the employees’ gross pay. You determine the
program should perform the following steps:
1. For each employee: get the number of hours worked and store it in a list element.
2. For each list element: use the value stored in the element to calculate an employee’s
gross pay. Display the amount of the gross pay.
Program 7-7 shows the code for the program.
NOTE: Suppose Megan’s business increases and she hires two additional baristas.
This would require you to change the program so it processes eight employees instead
of six. Because you used a constant for the list size, this is a simple modification—you
just change the statement in line 6 to read:
NUM_EMPLOYEES = 8
Because the NUM_EMPLOYEES constant is used in line 10 to create the list, the size of the
hours list will automatically become eight. Also, because you used the NUM_EMPLOYEES
constant to control the loop iterations in lines 13 and 21, the loops will automatically
iterate eight times, once for each employee.
Imagine how much more difficult this modification would be if you had not used a
constant to determine the list size. You would have to change each individual statement
in the program that refers to the list size. Not only would this require more work, but it
would open the possibility for errors. If you overlooked any one of the statements that
refer to the list size, a bug would occur.
Program Output
The total of the elements is 30.
Program Output
The average of the elements is 5.3.
17
18 # Calculate the total of the list elements.
19 for num in value_list:
20 total += num
21
22 # Return the total.
23 return total
24
25 # Call the main function.
26 if _ _name_ _ == '_ _main_ _':
27 main()
Program Output
The total is 30.
18
19 # Create a variable to control the loop.
20 again = 'y'
21
22 # Get values from the user and add them to
23 # the list.
24 while again == 'y':
25 # Get a number and add it to the list.
26 num = int(input('Enter a number: '))
27 values.append(num)
28
29 # Want to do this again?
30 print('Do you want to add another number?')
31 again = input('y = yes, anything else = no: ')
32 print()
33
34 # Return the list.
35 return values
36
37 # Call the main function.
38 if _ _name_ _ == '_ _main_ _':
39 main()
In the Spotlight:
Processing a List
Dr. LaClaire gives a series of exams during the semester in her chemistry class. At the end of
the semester, she drops each student’s lowest test score before averaging the scores. She has
asked you to design a program that will read a student’s test scores as input and calculate
the average with the lowest score dropped. Here is the algorithm that you developed:
Get the student’s test scores.
Calculate the total of the scores.
Find the lowest score.
Subtract the lowest score from the total. This gives the adjusted total.
Divide the adjusted total by 1 less than the number of test scores. This is the average.
Display the average.
Program 7-12 shows the code for the program, which is divided into three functions. Rather
than presenting the entire program at once, let’s first examine the main function, then each
additional function separately. Here is the main function:
Line 7 calls the get_scores function. The function gets the test scores from the user and
returns a reference to a list containing those scores. The list is assigned to the scores variable.
Line 10 calls the get_total function, passing the scores list as an argument. The function
returns the total of the values in the list. This value is assigned to the total variable.
Line 13 calls the built-in min function, passing the scores list as an argument. The function
returns the lowest value in the list. This value is assigned to the lowest variable.
Line 16 subtracts the lowest test score from the total variable. Then, line 21 calculates the
average by dividing total by len(scores) 2 1. (The program divides by len (scores) 2 1
because the lowest test score was dropped.) Lines 24 and 25 display the average.
Next is the get_scores function.
The get_scores function prompts the user to enter a series of test scores. As each score
is entered, it is appended to a list. The list is returned in line 50. Next is the get_total
function.
392 Chapter 7 Lists and Tuples
This function accepts a list as an argument. It uses an accumulator and a loop to calculate
the total of the values in the list. Line 64 returns the total.
selected element. To use the function, be sure to import the random module. The following
interactive session demonstrates:
>>> import random Enter
>>> names = ['Jenny', 'Kelly', 'Chloe', 'Aubrey'] Enter
>>> winner = random.choice(names) Enter
>>> print(winner) Enter
Chloe
>>>
The random module also provides a function named choices that returns multiple ran-
domly selected elements from a list. When you call the function, you pass a list and the
argument k=n, where n is the number of elements you want the function to return. The
function will then return a list of n randomly selected elements. The following interactive
session demonstrates:
>>> import random Enter
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> selected = random.choices(numbers, k=3)
>>> print(selected)
[8, 7, 7]
>>>
The list that is returned from the choices function sometimes contains duplicate elements.
If you want to randomly select unique elements, use the random module’s sample function
instead. The following interactive session demonstrates:
>>> import random Enter
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> selected = random.sample(numbers, k=3)
>>> print(selected)
[4, 10, 2]
>>>
After this program executes, the cities.txt file will contain the following line:
New YorkBostonAtlantaDallas
An alternative approach is to use the for loop to iterate through the list, writing each ele-
ment with a terminating newline character. Program 7-14 shows an example.
After this program executes, the cities.txt file will contain the following lines:
New York
Boston
Atlanta
Dallas
File objects in Python have a method named readlines that returns a file’s contents as
a list of strings. Each line in the file will be an item in the list. The items in the list will
include their terminating newline character, which in many cases you will want to strip.
Program 7-15 shows an example. The statement in line 8 reads the files contents into a
list, and the loop in lines 14 through 15 steps through the list, stripping the '\n' character
from each element.
Program Output
['New York', 'Boston', 'Atlanta', 'Dallas']
Program 7-16 shows another example of how a list can be written to a file. In this example,
a list of numbers is written. Notice in line 12, each item is converted to a string with the
str function, then a '\n' is concatenated to it. As an alternative, we could have written
line 12 using an f-string, as shown here:
outfile.write(f'{item}\n')
396 Chapter 7 Lists and Tuples
When you read numbers from a file into a list, the numbers will have to be converted from
strings to a numeric type. Program 7-17 shows an example.
Program Output
[1, 2, 3, 4, 5, 6, 7]
Some operations require you to read the contents of a list and use the values in that list to
produce a new list. For example, the following code makes a copy of a list:
list1 = [1, 2, 3, 4]
list2 = []
In this code, each time the loop iterates, it appends an element of list1 to list2. After
this code executes, list2 will reference a copy of list1.
Code like this can be written in a more concise, compact manner using a list comprehen-
sion. A list comprehension is an expression that reads an input list, using the values of the
input list to produce an output list. For example, the previously shown code can be written
using a list comprehension as follows:
list1 = [1, 2, 3, 4]
list2 = [item for item in list1]
The list comprehension expression appears in the second line of code, enclosed in brackets.
As shown in Figure 7-6, the list comprehension begins with a result expression, followed
by an iteration expression. The iteration expression works like a for loop. Each time it
iterates, the target variable item is assigned the value of an element. At the end of each
iteration, the value of the result expression is appended to the new list.
Result Iteration
expression expression
Let’s look at another example. Suppose you have a list of numbers and you want to create
a second list that contains the squares of all the numbers in the first list. The following code
shows how to accomplish this using a for loop:
list1 = [1, 2, 3, 4]
list2 = []
The following code shows how the same operation can be performed with a list comprehension:
list1 = [1, 2, 3, 4]
list2 = [item**2 for item in list1]
Figure 7-7 shows the iteration expression and the result expression. Each time the iteration
expression iterates, the target variable item is assigned the value of an element. At the end
of each iteration, the value of the result expression item**2 is appended to list2. After
this code executes, list2 will contain the values [1, 4, 9, 16].
Result Iteration
expression expression
Suppose you have a list of strings and you want to create a second list that contains the
lengths of all the strings in the first list. The following code shows how to accomplish this
using a for loop:
str_list = ['Winken', 'Blinken', 'Nod']
len_list = []
for s in str_list:
len_list.append(len(s))
The following code shows how the same operation can be performed with a list
comprehension:
str_list = ['Winken', 'Blinken', 'Nod']
len_list = [len(s) for s in str_list]
In the list comprehension, the iteration expression is for s in str_list and the
result expression is len(s). After this code executes, len_list will contain the values
[6, 7, 3].
for n in list1:
if n < 10:
list2.append(n)
The if statement that appears inside the for loop causes this code to append only the elements
that are less than 10 to list2. After this code executes, list2 will contain [1, 2, 3, 4].
This type of operation can also be accomplished by adding an if clause to a list comprehen-
sion. Here is the general format:
[result_expression iteration_expression if_clause]
The if clause acts as a filter, allowing you to select certain items from the input list. The
following code shows how we can rewrite the previous code using a list comprehension
with an if clause:
list1 = [1, 12, 2, 20, 3, 15, 4]
list2 = [item for item in list1 if item < 10]
In the list comprehension, the iteration expression is for item in list1, the if clause
is if item < 10, and the result expression is item. After this code executes, list2 will
contain [1, 2, 3, 4].
The following code shows another example:
last_names = ['Jackson', 'Smith', 'Hildebrandt', 'Jones']
short_names = [name for name in last_names if len(name) < 6]
The list comprehension, which iterates over the last_names list, has an if clause that
selects only the elements that are less than 6 characters long. After this code executes,
short_names will contain ['Smith', 'Jones']
Checkpoint
7.19 Look at the following list comprehension:
[x for x in my_list]
What is the result expression? What is the iteration expression?
7.20 After this code executes, what value will the list2 list hold?
list1 = [1, 12, 2, 20, 3, 15, 4]
list2 = [n*2 for n in list1]
7.21 After this code executes, what value will the list2 list hold?
list1 = [1, 12, 2, 20, 3, 15, 4]
list2 = [n for n in list1 if n > 10]
CONCEPT: A two-dimensional list is a list that has other lists as its elements.
The elements of a list can be virtually anything, including other lists. To demonstrate, look
at the following interactive session:
1 >>> students = [['Joe', 'Kim'], ['Sam', 'Sue'], ['Kelly', 'Chris']] Enter
2 >>> print(students) Enter
404 Chapter 7 Lists and Tuples
Checkpoint
7.22 Look at the following interactive session, in which a two-dimensional list is
created. How many rows and how many columns are in the list?
numbers = [[1, 2], [10, 20], [100, 200], [1000, 2000]]
7.23 Write a statement that creates a two-dimensional list with three rows and four
columns. Each element should be assigned the value 0.
7.24 Write a set of nested loops that display the contents of the numbers list shown in
Checkpoint question 7.22.
7.10 Tuples
CONCEPT: A tuple is an immutable sequence, which means that its contents cannot
be changed.
A tuple is a sequence, very much like a list. The primary difference between tuples and lists
is that tuples are immutable. That means once a tuple is created, it cannot be changed.
When you create a tuple, you enclose its elements in a set of parentheses, as shown in the
following interactive session:
>>> my_tuple = (1, 2, 3, 4, 5) Enter
>>> print(my_tuple) Enter
(1, 2, 3, 4, 5)
>>>
The first statement creates a tuple containing the elements 1, 2, 3, 4, and 5 and assigns it
to the variable my_tuple. The second statement sends my_tuple as an argument to the
print function, which displays its elements. The following session shows how a for loop
can iterate over the elements in a tuple:
>>> names = ('Holly', 'Warren', 'Ashley') Enter
>>> for n in names: Enter
print(n) Enter Enter
Holly
Warren
Ashley
>>>
Holly
Warren
Ashley
>>>
7.10 Tuples 405
In fact, tuples support all the same operations as lists, except those that change the contents
of the list. Tuples support the following:
• Subscript indexing (for retrieving element values only)
• Methods such as index
• Built-in functions such as len, min, and max
• Slicing expressions
• The in operator
• The + and * operators
Tuples do not support methods such as append, remove, insert, reverse, and sort.
NOTE: If you want to create a tuple with just one element, you must write a trailing
comma after the element’s value, as shown here:
my_tuple = (1,) # Creates a tuple with one element.
If you omit the comma, you will not create a tuple. For example, the following state-
ment simply assigns the integer value 1 to the value variable:
value = (1) # Creates an integer.
Checkpoint
7.25 What is the primary difference between a list and a tuple?
7.26 Give two reasons why tuples exist.
7.27 Assume my_list references a list. Write a statement that converts it to a tuple.
7.28 Assume my_tuple references a tuple. Write a statement that converts it to a list.
On a Mac or a Linux system, open a Terminal window and enter the following command:
sudo pip3 install matplotlib
TIP: See Appendix G for more information about packages and the pip utility.
Once you enter the command, the pip utility will start downloading and installing the
package. Once the process is finished, you can verify that the package was correctly
installed by starting IDLE and entering the command
>>> import matplotlib
If you do not see an error message, you can assume the package was successfully installed.
2
At the time this was written, there was an installation bug with matplotlib and Python 3.8.
If you have trouble installing matplotlib with Python 3.8, try installing an earlier version of
Python, such as 3.7.5
CHAPTER
TOPICS
8.1 Basic String Operations 8.3 Testing, Searching, and Manipulating
8.2 String Slicing Strings
Many of the programs that you have written so far have worked with strings, but only in
a limited way. The operations that you have performed with strings so far have primarily
involved only input and output. For example, you have read strings as input from the key-
board and from files, and sent strings as output to the screen and to files.
There are many types of programs that not only read strings as input and write strings as
output, but also perform operations on strings. Word processing programs, for example,
manipulate large amounts of text, and thus work extensively with strings. Email programs
and search engines are other examples of programs that perform operations on strings.
Python provides a wide variety of tools and programming techniques that you can use to
examine and manipulate strings. In fact, strings are a type of sequence, so many of the
concepts that you learned about sequences in Chapter 7 apply to strings as well. We will
look at many of these in this chapter.
431
432 Chapter 8 More About Strings
In the general format, variable is the name of a variable, and string is either a string
literal or a variable that references a string. Each time the loop iterates, variable will ref-
erence a copy of a character in string, beginning with the first character. We say that the
loop iterates over the characters in the string. Here is an example:
name = 'Juliet'
for ch in name:
print(ch)
The name variable references a string with six characters, so this loop will iterate six times.
The first time the loop iterates, the ch variable will reference 'J', the second time the loop
iterates the ch variable will reference 'u', and so forth. This is illustrated in Figure 8-1.
When the code executes, it will display the following:
J
u
l
i
e
t
8.1 Basic String Operations 433
ch 'J' ch 'u'
NOTE: Figure 8-1 illustrates how the ch variable references a copy of a character
from the string as the loop iterates. If we change the value that ch references in the loop,
it has no effect on the string referenced by name. To demonstrate, look at the following:
1 name = 'Juliet'
2 for ch in name:
3 ch = 'X'
4 print(name)
The statement in line 3 merely reassigns the ch variable to a different value each time
the loop iterates. It has no effect on the string 'Juliet' that is referenced by name, and
it has no effect on the number of times the loop iterates. When this code executes, the
statement in line 4 will print:
Juliet
Program 8-1 shows another example. This program asks the user to enter a string. It then
uses a for loop to iterate over the string, counting the number of times that the letter T
(uppercase or lowercase) appears.
434 Chapter 8 More About Strings
Indexing
Another way that you can access the individual characters in a string is with an index. Each
character in a string has an index that specifies its position in the string. Indexing starts
at 0, so the index of the first character is 0, the index of the second character is 1, and so
forth. The index of the last character in a string is 1 less than the number of characters in
the string. Figure 8-2 shows the indexes for each character in the string 'Roses are red'.
The string has 13 characters, so the character indexes range from 0 through 12.
You can use an index to retrieve a copy of an individual character in a string, as shown here:
my_string = 'Roses are red'
ch = my_string[6]
8.1 Basic String Operations 435
The expression my_string[6] in the second statement returns a copy of the character at
index 6 in my_string. After this statement executes, ch will reference 'a' as shown in
Figure 8-3.
ch 'a'
You can also use negative numbers as indexes, to identify character positions relative to
the end of the string. The Python interpreter adds negative indexes to the length of the string
to determine the character position. The index −1 identifies the last character in a string, −2
identifies the next to last character, and so forth. The following code shows an example:
my_string = 'Roses are red'
print(my_string[−1], my_string[−2], my_string[−13])
IndexError Exceptions
An IndexError exception will occur if you try to use an index that is out of range for a
particular string. For example, the string 'Boston' has 6 characters, so the valid indexes
are 0 through 5. (The valid negative indexes are −1 through −6.) The following is an
example of code that causes an IndexError exception:
city = 'Boston'
print(city[6])
This type of error is most likely to happen when a loop incorrectly iterates beyond the end
of a string, as shown here:
city = 'Boston'
index = 0
while index < 7:
print(city[index])
index += 1
The last time that this loop iterates, the index variable will be assigned the value 6, which
is an invalid index for the string 'Boston'. As a result, the print function will cause an
IndexError exception to be raised.
436 Chapter 8 More About Strings
city = 'Boston'
size = len(city)
The second statement calls the len function, passing the city variable as an argument.
The function returns the value 6, which is the length of the string 'Boston'. This value is
assigned to the size variable.
The len function is especially useful to prevent loops from iterating beyond the end of a
string, as shown here:
city = 'Boston'
index = 0
while index < len(city):
print(city[index])
index += 1
Notice the loop iterates as long as index is less than the length of the string. This is because
the index of the last character in a string is always 1 less than the length of the string.
String Concatenation
A common operation that performed on strings is concatenation, or appending one string
to the end of another string. You have seen examples in earlier chapters that use the +
operator to concatenate strings. The + operator produces a string that is the combination
of the two strings used as its operands. The following interactive session demonstrates:
1 >>> message = 'Hello ' + 'world' Enter
2 >>> print(message) Enter
3 Hello world
4 >>>
Line 1 concatenates the strings 'Hello' and 'world' to produce the string 'Hello world'.
The string 'Hello world' is then assigned to the message variable. Line 2 prints the string
that is referenced by the message variable. The output is shown in line 3.
Here is another interactive session that demonstrates concatenation:
1 >>> first_name = 'Emily' Enter
2 >>> last_name = 'Yeager' Enter
3 >>> full_name = first_name + ' ' + last_name Enter
4 >>> print(full_name) Enter
5 Emily Yeager
6 >>>
Line 1 assigns the string 'Emily' to the first_name variable. Line 2 assigns the string
'Yeager' to the last_name variable. Line 3 produces a string that is the concatenation of
first_name, followed by a space, followed by last_name. The resulting string is assigned
to the full_name variable. Line 4 prints the string referenced by full_name. The output
is shown in line 5.
8.1 Basic String Operations 437
You can also use the += operator to perform concatenation. The following interactive ses-
sion demonstrates:
1 >>> letters = 'abc' Enter
2 >>> letters += 'def' Enter
3 >>> print(letters) Enter
4 abcdef
5 >>>
After the statement in line 2 executes, the letters variable will reference the string 'abcdef'.
Here is another example:
>>> name = 'Kelly' Enter # name is 'Kelly'
>>> name += ' ' Enter # name is 'Kelly '
>>> name += 'Yvonne' Enter # name is 'Kelly Yvonne'
>>> name += ' ' Enter # name is 'Kelly Yvonne '
>>> name += 'Smith' Enter # name is 'Kelly Yvonne Smith'
>>> print(name) e
Kelly Yvonne Smith
>>>
Keep in mind that the operand on the left side of the += operator must be an existing vari-
able. If you specify a nonexistent variable, an exception is raised.
Program Output
The name is: Carmen
Now the name is: Carmen Brown
438 Chapter 8 More About Strings
The statement in line 4 assigns the string 'Carmen' to the name variable, as shown
in Figure 8-4. The statement in line 6 concatenates the string ' Brown' to the string
'Carmen' and assigns the result to the name variable, as shown in Figure 8-5. As you can
see from the figure, the original string 'Carmen' is not modified. Instead, a new string con-
taining 'Carmen Brown' is created and assigned to the name variable. (The original string,
'Carmen' is no longer usable because no variable references it. The Python interpreter will
eventually remove the unusable string from memory.)
name = 'Carmen'
name Carmen
name Carmen
Carmen Brown
Because strings are immutable, you cannot use an expression in the form string[index]
on the left side of an assignment operator. For example, the following code will cause an
error:
# Assign 'Bill' to friend.
friend = 'Bill'
# Can we change the first character to 'J'?
friend[0] = 'J' # No, this will cause an error!
The last statement in this code will raise an exception because it attempts to change the
value of the first character in the string 'Bill'.
Checkpoint
8.1 Assume the variable name references a string. Write a for loop that prints each
character in the string.
8.2 What is the index of the first character in a string?
8.3 If a string has 10 characters, what is the index of the last character?
8.4 What happens if you try to use an invalid index to access a character in a string?
8.5 How do you find the length of a string?
8.6 What is wrong with the following code?
animal = 'Tiger'
animal[0] = 'L'
8.2 String Slicing 439
You learned in Chapter 7 that a slice is a span of items that are taken from a sequence.
When you take a slice from a string, you get a span of characters from within the string.
String slices are also called substrings.
To get a slice of a string, you write an expression in the following general format:
string[start : end]
In the general format, start is the index of the first character in the slice, and end is the
index marking the end of the slice. The expression will return a string containing a copy
of the characters from start up to (but not including) end. For example, suppose we have
the following:
full_name = 'Patty Lynn Smith'
middle_name = full_name[6:10]
The second statement assigns the string 'Lynn' to the middle_name variable. If you leave
out the start index in a slicing expression, Python uses 0 as the starting index. Here is an
example:
full_name = 'Patty Lynn Smith'
first_name = full_name[:5]
The second statement assigns the string 'Patty' to first_name. If you leave out the end
index in a slicing expression, Python uses the length of the string as the end index. Here is
an example:
full_name = 'Patty Lynn Smith'
last_name = full_name[11:]
The second statement assigns the string 'Smith' to last_name. What do you think the
following code will assign to the my_string variable?
full_name = 'Patty Lynn Smith'
my_string = full_name[:]
The second statement assigns the entire string 'Patty Lynn Smith' to my_string. The
statement is equivalent to:
my_string = full_name[0 : len(full_name)]
The slicing examples we have seen so far get slices of consecutive characters from strings.
Slicing expressions can also have step value, which can cause characters to be skipped in the
string. Here is an example of code that uses a slicing expression with a step value:
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
print(letters[0:26:2])
The third number inside the brackets is the step value. A step value of 2, as used in this
example, causes the slice to contain every second character from the specified range in the
string. The code will print the following:
ACEGIKMOQSUWY
440 Chapter 8 More About Strings
You can also use negative numbers as indexes in slicing expressions to reference positions
relative to the end of the string. Here is an example:
full_name = 'Patty Lynn Smith'
last_name = full_name[−5:]
Recall that Python adds a negative index to the length of a string to get the position refer-
enced by that index. The second statement in this code assigns the string 'Smith' to the
last_name variable.
NOTE: Invalid indexes do not cause slicing expressions to raise an exception. For
example:
• If the end index specifies a position beyond the end of the string, Python will use the
length of the string instead.
• If the start index specifies a position before the beginning of the string, Python will
use 0 instead.
• If the start index is greater than the end index, the slicing expression will return
an empty string.
In the Spotlight:
Extracting Characters from a String
At a university, each student is assigned a system login name, which the student uses to log
into the campus computer system. As part of your internship with the university’s Informa-
tion Technology department, you have been asked to write the code that generates system
login names for students. You will use the following algorithm to generate a login name:
1. Get the first three characters of the student’s first name. (If the first name is less than
three characters in length, use the entire first name.)
2. Get the first three characters of the student’s last name. (If the last name is less than
three characters in length, use the entire last name.)
3. Get the last three characters of the student’s ID number. (If the ID number is less
than three characters in length, use the entire ID number.)
4. Concatenate the three sets of characters to generate the login name.
For example, if a student’s name is Amanda Spencer, and her ID number is ENG6721, her
login name would be AmaSpe721. You decide to write a function named get_login_name
that accepts a student’s first name, last name, and ID number as arguments, and returns the
student’s login name as a string. You will save the function in a module named login.py.
This module can then be imported into any Python program that needs to generate a login
name. Program 8-3 shows the code for the login.py module.
The get_login_name function accepts three string arguments: a first name, a last name,
and an ID number. The statement in line 9 uses a slicing expression to get the first three
characters of the string referenced by first and assigns those characters, as a string, to
the set1 variable. If the string referenced by first is less than three characters long, then
the value 3 will be an invalid ending index. If this is the case, Python will use the length
of the string as the ending index, and the slicing expression will return the entire string.
The statement in line 14 uses a slicing expression to get the first three characters of the
string referenced by last, and assigns those characters, as a string, to the set2 variable.
The entire string referenced by last will be returned if it is less than three characters.
The statement in line 19 uses a slicing expression to get the last three characters of the string
referenced by idnumber and assigns those characters, as a string, to the set3 variable. If
the string referenced by idnumber is less than three characters, then the value −3 will be an
invalid starting index. If this is the case, Python will use 0 as the starting index.
The statement in line 22 assigns the concatenation of set1, set2, and set3 to the login_
name variable. The variable is returned in line 25. Program 8-4 shows a demonstration of
the function.
1 # This program gets the user's first name, last name, and
2 # student ID number. Using this data it generates a
3 # system login name.
4
5 import login
(program continues)
442 Chapter 8 More About Strings
6
7 def main():
8 # Get the user's first name, last name, and ID number.
9 first = input('Enter your first name: ')
10 last = input('Enter your last name: ')
11 idnumber = input('Enter your student ID number: ')
12
13 # Get the login name.
14 print('Your system login name is:')
15 print(login.get_login_name(first, last, idnumber))
16
17 # Call the main function.
18 if _ _name_ _ == '_ _main_ _':
19 main()
Checkpoint
8.7 What will the following code display?
mystring = 'abcdefg'
print(mystring[2:5])
8.8 What will the following code display?
mystring = 'abcdefg'
print(mystring[3:])
8.9 What will the following code display?
mystring = 'abcdefg'
print(mystring[:3])
8.10 What will the following code display?
mystring = 'abcdefg'
print(mystring[:])
8.3 Testing, Searching, and Manipulating Strings 443
CONCEPT: Python provides operators and methods for testing strings, searching the
contents of strings, and getting modified copies of strings.
string1 and string2 can be either string literals or variables referencing strings. The expres-
sion returns true if string1 is found in string2. For example, look at the following code:
text = 'Four score and seven years ago'
if 'seven' in text:
print('The string "seven" was found.')
else:
print('The string "seven" was not found.')
This code determines whether the string 'Four score and seven years ago' contains
the string 'seven'. If we run this code, it will display:
The string "seven" was found.
You can use the not in operator to determine whether one string is not contained in
another string. Here is an example:
names = 'Bill Joanne Susan Chris Juan Katie'
if 'Pierre' not in names:
print('Pierre was not found.')
else:
print('Pierre was found.')
String Methods
Recall from Chapter 6 that a method is a function that belongs to an object and performs
some operation on that object. Strings in Python have numerous methods.1 In this section,
we will discuss several string methods for performing the following types of operations:
• Testing the values of strings
• Performing various modifications
• Searching for substrings and replacing sequences of characters
1
We do not cover all of the string methods in this book. For a comprehensive list of string methods,
see the Python documentation at www.python.org.
444 Chapter 8 More About Strings
In the general format, stringvar is a variable that references a string, method is the name
of the method that is being called, and arguments is one or more arguments being passed
to the method. Let’s look at some examples.
Program 8-5 demonstrates several of the string testing methods. It asks the user to enter a string
then displays various messages about the string, depending on the return value of the methods.
Modification Methods
Although strings are immutable, meaning they cannot be modified, they do have a number of
methods that return modified versions of themselves. Table 8-2 lists several of these methods.
For example, the lower method returns a copy of a string with all of its alphabetic letters
converted to lowercase. Here is an example:
letters = 'WXYZ'
print(letters, letters.lower())
The upper method returns a copy of a string with all of its alphabetic letters converted to
uppercase. Here is an example:
letters = 'abcd'
print(letters, letters.upper())
The lower and upper methods are useful for making case-insensitive string compari
sons. String comparisons are case-sensitive, which means the uppercase c haracters are
8.3 Testing, Searching, and Manipulating Strings 447
Notice the last statement in the loop asks the user to enter y to see the message displayed
again. The loop iterates as long as the expression again.lower() =='y' is true. The
expression will be true if the again variable references either 'y' or 'Y'.
Similar results can be achieved by using the upper method, as shown here:
again = 'y'
while again.upper() == 'Y':
print('Hello')
print('Do you want to see that again?')
again = input('y = yes, anything else = no: ')
The endswith method determines whether a string ends with a specified substring. Here
is an example:
filename = input('Enter the filename: ')
if filename.endswith('.txt'):
print('That is the name of a text file.')
elif filename.endswith('.py'):
print('That is the name of a Python source file.')
elif filename.endswith('.doc'):
print('That is the name of a word processing document.')
else:
print('Unknown file type.')
The startswith method works like the endswith method, but determines whether a
string begins with a specified substring.
The find method searches for a specified substring within a string. The method returns
the lowest index of the substring, if it is found. If the substring is not found, the method
returns −1. Here is an example:
string = 'Four score and seven years ago'
position = string.find('seven')
if position != −1:
print(f’The word “seven” was found at index {position}.’)
else:
print('The word "seven" was not found.')
The replace method returns a copy of a string, where every occurrence of a specified
substring has been replaced with another string. For example, look at the following code:
string = 'Four score and seven years ago'
new_string = string.replace('years', 'days')
print(new_string)
In the Spotlight:
Validating the Characters in a Password
At the university, passwords for the campus computer system must meet the following
requirements:
• The password must be at least seven characters long.
• It must contain at least one uppercase letter.
8.3 Testing, Searching, and Manipulating Strings 449
56
57 # Determine whether all of the requirements
58 # are met. If they are, set is_valid to true.
59 # Otherwise, set is_valid to false.
60 if correct_length and has_uppercase and \
61 has_lowercase and has_digit:
62 is_valid = True
63 else:
64 is_valid = False
65
66 # Return the is_valid variable.
67 return is_valid
Program 8-7 imports the login module and demonstrates the valid_password function.
The repetition operator creates a string that contains n repeated copies of string_to_copy.
Here is an example:
my_string = 'w' * 5
After this statement executes, my_string will reference the string 'wwwww'. Here is another
example:
print('Hello' * 5)
Program Output
Z
ZZ
ZZZ
ZZZZ
ZZZZZ
ZZZZZZ
ZZZZZZZ
ZZZZZZZZ
ZZZZZZZZZ
ZZZZZZZZ
8.3 Testing, Searching, and Manipulating Strings 453
ZZZZZZZ
ZZZZZZ
ZZZZZ
ZZZZ
ZZZ
ZZ
Z
Splitting a String
Strings in Python have a method named split that returns a list containing the words in
the string. Program 8-9 shows an example.
Program Output
['One', 'two', 'three', 'four']
By default, the split method uses spaces as separators (that is, it returns a list of the words in
the string that are separated by spaces). You can specify a different separator by passing it as
an argument to the split method. For example, suppose a string contains a date, as shown here:
date_string = '11/26/2020'
If you want to break out the month, day, and year as items in a list, you can call the split
method using the '/' character as a separator, as shown here:
date_list = date_string.split('/')
After this statement executes, the date_list variable will reference this list:
['11', '26', '2020']
454 Chapter 8 More About Strings
Program Output
Month: 11
Day: 26
Year: 2020
In the Spotlight:
String Tokens
Sometimes a string will contain a series of words or other items of data separated by spaces
or other characters. For example, look at the following string:
'peach raspberry strawberry vanilla'
This string contains the following four items of data: peach, raspberry, strawberry, and
vanilla. In programming terms, items such as these are known as tokens. Notice a space ap-
pears between the items. The character that separates tokens is known as a delimiter. Here
is another example:
'17;92;81;12;46;5'
This string contains the following tokens: 17, 92, 81, 12, 46, and 5. Notice a semicolon appears
between each item. In this example, the semicolon is used as a delimiter. Some programming
problems require you to read a string that contains a list of items then extract all the tokens
from the string for processing. For example, look at the following string that contains a date:
'3–22–2021'
CHAPTER
TOPICS
9.1 Dictionaries
9.2 Sets
9.3 Serializing Objects
9.1 Dictionaries
When you hear the word “dictionary,” you probably think about a large book such as the
Merriam-Webster dictionary, containing words and their definitions. If you want to know
VideoNote
Introduction to the meaning of a particular word, you locate it in the dictionary to find its definition.
Dictionaries
In Python, a dictionary is an object that stores a collection of data. Each element that is
stored in a dictionary has two parts: a key and a value. In fact, dictionary elements are
commonly referred to as key-value pairs. When you want to retrieve a specific value from a
dictionary, you use the key that is associated with that value. This is similar to the process
of looking up a word in the Merriam-Webster dictionary, where the words are keys and
the definitions are values.
For example, suppose each employee in a company has an ID number, and we want to write
a program that lets us look up an employee’s name by entering that employee’s ID number.
We could create a dictionary in which each element contains an employee ID number as
the key, and that employee’s name as the value. If we know an employee’s ID number, then
we can retrieve that employee’s name.
Another example would be a program that lets us enter a person’s name and gives us that
person’s phone number. The program could use a dictionary in which each element contains
a person’s name as the key, and that person’s phone number as the value. If we know a
person’s name, then we can retrieve that person’s phone number.
467
468 Chapter 9 Dictionaries and Sets
NOTE : Key-value pairs are often referred to as mappings because each key is mapped
to a value.
Creating a Dictionary
You can create a dictionary by enclosing the elements inside a set of curly braces ( {} ).
An element consists of a key, followed by a colon, followed by a value. The elements are
separated by commas. The following statement shows an example:
phonebook = {'Chris':'555−1111', 'Katie':'555−2222', 'Joanne':'555−3333'}
This statement creates a dictionary and assigns it to the phonebook variable. The dictionary
contains the following three elements:
• The first element is 'Chris':'555−1111'. In this element, the key is 'Chris' and
the value is '555−1111'.
• The second element is 'Katie':'555−2222'. In this element, the key is 'Katie' and
the value is '555−2222'.
• The third element is 'Joanne':'555−3333'. In this element, the key is 'Joanne' and
the value is '555−3333'.
In this example, the keys and the values are strings. The values in a dictionary can be
objects of any type, but the keys must be immutable objects. For example, keys can be
strings, integers, floating-point values, or tuples. Keys cannot be lists or any other type of
immutable object.
Notice the order in which the elements are displayed is different than the order in which
they were created. This illustrates how dictionaries are not sequences, like lists, tuples, and
strings. As a result, you cannot use a numeric index to retrieve a value by its position from
a dictionary. Instead, you use a key to retrieve a value.
To retrieve a value from a dictionary, you simply write an expression in the following
general format:
dictionary_name[key]
In the general format, dictionary_name is the variable that references the dictionary,
and key is a key. If the key exists in the dictionary, the expression returns the value that is
9.1 Dictionaries 469
associated with the key. If the key does not exist, a KeyError exception is raised. The
following interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222',
'Joanne':'555−3333'} Enter
2 >>> phonebook['Chris'] Enter
3 '555−1111'
4 >>> phonebook['Joanne'] Enter
5 '555−3333'
6 >>> phonebook['Katie'] Enter
7 '555−2222'
8 >>> phonebook['Kathryn'] Enter
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
phonebook['Kathryn']
KeyError: 'Kathryn'
>>>
NOTE: Remember that string comparisons are case sensitive. The expression
phonebook['katie'] will not locate the key 'Katie' in the dictionary.
The if statement in line 2 determines whether the key 'Chris' is in the phonebook
dictionary. If it is, the statement in line 3 displays the value that is associated with that key.
You can also use the not in operator to determine whether a key does not exist, as dem-
onstrated in the following session:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222'} Enter
2 >>> if 'Joanne' not in phonebook: Enter
3 print('Joanne is not found.') Enter Enter
4
5 Joanne is not found.
6 >>>
NOTE: Keep in mind that string comparisons with the in and not in operators are
case sensitive.
In the general format, dictionary_name is the variable that references the dictionary, and
key is a key. If key already exists in the dictionary, its associated value will be changed to
value. If the key does not exist, it will be added to the dictionary, along with value as its
associated value. The following interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222',
'Joanne':'555−3333'} Enter
2 >>> phonebook['Joe'] = '555−0123' Enter
3 >>> phonebook['Chris'] = '555−4444' Enter
4 >>> phonebook Enter
5 {'Chris': '555−4444', 'Joanne': '555−3333', 'Joe': '555−0123',
'Katie': '555−2222'}
6 >>>
NOTE: You cannot have duplicate keys in a dictionary. When you assign a value to
an existing key, the new value replaces the existing value.
9.1 Dictionaries 471
Deleting Elements
You can delete an existing key-value pair from a dictionary with the del statement. Here
is the general format:
del dictionary_name[key]
In the general format, dictionary_name is the variable that references the dictionary, and
key is a key. After the statement executes, the key and its associated value will be deleted
from the dictionary. If the key does not exist, a KeyError exception is raised. The following
interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222',
'Joanne':'555−3333'} Enter
2 >>> phonebook Enter
3 {'Chris': '555−1111', 'Joanne': '555−3333', 'Katie': '555−2222'}
4 >>> del phonebook['Chris'] Enter
5 >>> phonebook Enter
6 {'Joanne': '555−3333', 'Katie': '555−2222'}
7 >>> del phonebook['Chris'] Enter
8 Traceback (most recent call last):
9 File "<pyshell#5>", line 1, in <module>
10 del phonebook['Chris']
11 KeyError: 'Chris'
12 >>>
Let’s take a closer look at the session:
• Line 1 creates a dictionary, and line 2 displays its contents.
• Line 4 deletes the element with the key 'Chris', and line 5 displays the contents of
the dictionary. You can see in the output in line 6 that the element no longer exists in
the dictionary.
• Line 7 tries to delete the element with the key 'Chris' again. Because the element no
longer exists, a KeyError exception is raised.
To prevent a KeyError exception from being raised, you should use the in operator to
determine whether a key exists before you try to delete it and its associated value. The fol-
lowing interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222',
'Joanne':'555−3333'} Enter
2 >>> if 'Chris' in phonebook: Enter
3 del phonebook['Chris'] Enter Enter
4
5 >>> phonebook Enter
6 {'Joanne': '555−3333', 'Katie': '555−2222'}
7 >>>
Let’s take a closer look at the session. This statement in lines 1 through 4 creates a dictio-
nary and assigns it to the test_scores variable. The dictionary contains the following
four elements:
• The first element is 'Kayla' : [88, 92, 100]. In this element, the key is 'Kayla'
and the value is the list [88, 92, 100].
• The second element is 'Luis' : [95, 74, 81]. In this element, the key is 'Luis'
and the value is the list [95, 74, 81].
• The third element is 'Sophie' : [72, 88, 91]. In this element, the key is 'Sophie'
and the value is the list [72, 88, 91].
• The fourth element is 'Ethan' : [70, 75, 78]. In this element, the key is 'Ethan'
and the value is the list [70, 75, 78].
Here is a summary of the rest of the session:
• Line 5 displays the contents of the dictionary, as shown in lines 6 through 7.
• Line 8 retrieves the value that is associated with the key 'Sophie'. The value is
displayed in line 9.
9.1 Dictionaries 473
• Line 10 retrieves the value that is associated with the key 'Kayla' and assigns it to
the kayla_scores variable. After this statement executes, the kayla_scores variable
references the list [88, 92, 100].
• Line 11 passes the kayla_scores variable to the print function. The function’s out-
put is shown in line 12.
The values that are stored in a single dictionary can be of different types. For example, one
element’s value might be a string, another element’s value might be a list, and yet another
element’s value might be an integer. The keys can be of different types, too, as long as they
are immutable. The following interactive session demonstrates how different types can be
mixed in a dictionary:
1 >>> mixed_up = {'abc':1, 999:'yada yada', (3, 6, 9):[3, 6, 9]} Enter
2 >>> mixed_up Enter
3 {(3, 6, 9): [3, 6, 9], 'abc': 1, 999: 'yada yada'}
4 >>>
This statement in line 1 creates a dictionary and assigns it to the mixed_up variable. The
dictionary contains the following elements:
• The first element is 'abc':1. In this element, the key is the string 'abc' and the value
is the integer 1.
• The second element is 999:'yada yada'. In this element, the key is the integer 999
and the value is the string 'yada yada'.
• The third element is (3, 6, 9):[3, 6, 9]. In this element, the key is the tuple
(3, 6, 9) and the value is the list [3, 6, 9].
The following interactive session gives a more practical example. It creates a dictionary that
contains various pieces of data about an employee:
1 >>> employee = {'name' : 'Kevin Smith', 'id' : 12345, 'payrate' :
25.75 } Enter
2 >>> employee Enter
3 {'payrate': 25.75, 'name': 'Kevin Smith', 'id': 12345}
4 >>>
This statement in line 1 creates a dictionary and assigns it to the employee variable. The
dictionary contains the following elements:
• The first element is 'name' : 'Kevin Smith'. In this element, the key is the string
'name' and the value is the string 'Kevin Smith'.
• The second element is 'id' : 12345. In this element, the key is the string 'id' and
the value is the integer 12345.
• The third element is 'payrate' : 25.75. In this element, the key is the string
'payrate' and the value is the floating-point number 25.75.
The statement in line 1 creates an empty dictionary and assigns it to the phonebook vari-
able. Lines 2 through 4 add key-value pairs to the dictionary, and the statement in line 5
displays the dictionary’s contents.
You can also use the built-in dict() method to create an empty dictionary, as shown in
the following statement:
phonebook = dict()
After this statement executes, the phonebook variable will reference an empty dictionary.
In the general format, var is the name of a variable and dictionary is the name of a
dictionary. This loop iterates once for each element in the dictionary. Each time the loop
iterates, var is assigned a key. The following interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> for key in phonebook: Enter
5 print(key) Enter Enter
6
7
8 Chris
9 Joanne
10 Katie
11 >>> for key in phonebook: Enter
12 print(key, phonebook[key]) Enter Enter
13
14
15 Chris 555−1111
16 Joanne 555−3333
17 Katie 555−2222
18 >>>
• Lines 4 through 5 contain a for loop that iterates once for each element of the
phonebook dictionary. Each time the loop iterates, the key variable is assigned a key.
Line 5 prints the value of the key variable. Lines 8 through 9 show the output of the
loop.
• Lines 11 through 12 contain another for loop that iterates once for each element of
the phonebook dictionary, assigning a key to the key variable. Line 5 prints the key
variable, followed by the value that is associated with that key. Lines 15 through 17
show the output of the loop.
Notice after the statement in line 4 executes, the phonebook dictionary contains no
elements.
In the general format, dictionary is the name of a dictionary, key is a key to search for
in the dictionary, and default is a default value to return if the key is not found. When
the method is called, it returns the value that is associated with the specified key. If the
specified key is not found in the dictionary, the method returns default. The following
interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', 'Katie':'555−2222'} Enter
2 >>> value = phonebook.get('Katie', 'Entry not found') Enter
3 >>> print(value) Enter
4 555−2222
5 >>> value = phonebook.get('Andy', 'Entry not found') Enter
6 >>> print(value) Enter
7 Entry not found
8 >>>
You can use the for loop to iterate over the tuples in the sequence. The following interac-
tive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> for key, value in phonebook.items(): Enter
5 print(key, value) Enter Enter
6
7
8 Chris 555−1111
9 Joanne 555−3333
10 Katie 555−2222
11 >>>
The following interactive session shows how you can use a for loop to iterate over the
sequence that is returned from the keys method:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> for key in phonebook.keys(): Enter
5 print(key) Enter Enter
6
7
8 Chris
9 Joanne
10 Katie
11 >>>
478 Chapter 9 Dictionaries and Sets
In the general format, dictionary is the name of a dictionary, key is a key to search for
in the dictionary, and default is a default value to return if the key is not found. When
the method is called, it returns the value that is associated with the specified key, and it
removes that key-value pair from the dictionary. If the specified key is not found in the
dictionary, the method returns default. The following interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> phone_num = phonebook.pop('Chris', 'Entry not found') Enter
5 >>> phone_num Enter
6 '555−1111'
7 >>> phonebook Enter
8 {'Joanne': '555−3333', 'Katie': '555−2222'}
9 >>> phone_num = phonebook.pop('Andy', 'Element not found') Enter
10 >>> phone_num Enter
11 'Element not found'
12 >>> phonebook Enter
13 {'Joanne': '555−3333', 'Katie': '555−2222'}
14 >>>
You can use an assignment statement in the following general format to assign the returned
key and value to individual variables:
k, v = dictionary.popitem()
This type of assignment is known as a multiple assignment because multiple variables are
being assigned at once. In the general format, k and v are variables. After the statement
executes, k is assigned a randomly selected key from the dictionary, and v is assigned
the value associated with that key. The key-value pair is removed from the dictionary.
The following interactive session demonstrates:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> phonebook Enter
5 {'Chris': '555−1111', 'Joanne': '555−3333', 'Katie': '555−2222'}
6 >>> key, value = phonebook.popitem() Enter
7 >>> print(key, value) Enter
8 Chris 555−1111
9 >>> phonebook Enter
10 {'Joanne': '555−3333', 'Katie': '555−2222'}
11 >>>
The following interactive session shows how you can use a for loop to iterate over the
sequence that is returned from the values method:
1 >>> phonebook = {'Chris':'555−1111', Enter
2 'Katie':'555−2222', Enter
3 'Joanne':'555−3333'} Enter
4 >>> for val in phonebook.values(): Enter
5 print(val) Enter Enter
6
7
8 555−1111
9 555−3333
10 555−2222
11 >>>
In the Spotlight:
Using a Dictionary to Simulate a Deck of Cards
In some games involving poker cards, the cards are assigned numeric values. For example,
in the game of Blackjack, the cards are given the following numeric values:
• Numeric cards are assigned the value they have printed on them. For example, the
value of the 2 of spades is 2, and the value of the 5 of diamonds is 5.
• Jacks, queens, and kings are valued at 10.
• Aces are valued at either 1 or 11, depending on the player’s choice.
In this section, we look at a program that uses a dictionary to simulate a standard deck of
poker cards, where the cards are assigned numeric values similar to those used in Blackjack.
(In the program, we assign the value 1 to all aces.) The key-value pairs use the name of the
card as the key, and the card’s numeric value as the value. For example, the key-value pair
for the queen of hearts is
'Queen of Hearts':10
9.2 Sets
A set is an object that stores a collection of data in the same way as mathematical sets. Here
are some important things to know about sets:
VideoNote
Introduction
to Sets • All the elements in a set must be unique. No two elements can have the same value.
• Sets are unordered, which means that the elements in a set are not stored in any par-
ticular order.
• The elements that are stored in a set can be of different data types.
494 Chapter 9 Dictionaries and Sets
Creating a Set
To create a set, you have to call the built-in set function. Here is an example of how you
create an empty set:
myset = set()
After this statement executes, the myset variable will reference an empty set. You can also
pass one argument to the set function. The argument that you pass must be an object that
contains iterable elements, such as a list, a tuple, or a string. The individual elements of
the object that you pass as an argument become elements of the set. Here is an example:
myset = set(['a', 'b', 'c'])
In this example, we are passing a list as an argument to the set function. After this statement
executes, the myset variable references a set containing the elements 'a', 'b', and 'c'.
If you pass a string as an argument to the set function, each individual character in the
string becomes a member of the set. Here is an example:
myset = set('abc')
After this statement executes, the myset variable will reference a set containing the elements
'a', 'b', and 'c'.
Sets cannot contain duplicate elements. If you pass an argument containing duplicate
elements to the set function, only one of the duplicated elements will appear in the set.
Here is an example:
myset = set('aaabc')
The character 'a' appears multiple times in the string, but it will appear only once in the
set. After this statement executes, the myset variable will reference a set containing the
elements 'a', 'b', and 'c'.
What if you want to create a set in which each element is a string containing more than one
character? For example, how would you create a set containing the elements 'one', 'two',
and 'three'? The following code does not accomplish the task, because you can pass no
more than one argument to the set function:
# This is an ERROR!
myset = set('one', 'two', 'three')
After this statement executes, the myset variable will reference a set containing the ele-
ments 'o', 'n', 'e', ' ', 't', 'w', 'h', and 'r'. To create the set that we want, we have
to pass a list containing the strings ‘one’, ‘two’, and ‘three’ as an argument to the set
function. Here is an example:
# OK, this works.
myset = set(['one', 'two', 'three'])
After this statement executes, the myset variable will reference a set containing the ele-
ments 'one', 'two', and 'three'.
9.2 Sets 495
The statement in line 1 creates an empty set and assigns it to the myset variable. The state-
ments in lines 2 through 4 add the values 1, 2, and 3 to the set. Line 5 displays the contents
of the set, which is shown in line 6.
The statement in line 7 attempts to add the value 2 to the set. The value 2 is already in the
set, however. If you try to add a duplicate item to a set with the add method, the method
does not raise an exception. It simply does not add the item.
You can add a group of elements to a set all at one time with the update method. When
you call the update method as an argument, you pass an object that contains iterable ele-
ments, such as a list, a tuple, string, or another set. The individual elements of the object
that you pass as an argument become elements of the set. The following interactive session
demonstrates:
1 >>> myset = set([1, 2, 3]) Enter
2 >>> myset.update([4, 5, 6]) Enter
3 >>> myset Enter
4 {1, 2, 3, 4, 5, 6}
5 >>>
The statement in line 1 creates a set containing the values 1, 2, and 3. Line 2 adds the values
4, 5, and 6. The following session shows another example:
1 >>> set1 = set([1, 2, 3]) Enter
2 >>> set2 = set([8, 9, 10]) Enter
3 >>> set1.update(set2) Enter
496 Chapter 9 Dictionaries and Sets
4 >>> set1
5 {1, 2, 3, 8, 9, 10}
6 >>> set2 Enter
7 {8, 9, 10}
8 >>>
Line 1 creates a set containing the values 1, 2, and 3 and assigns it to the set1 variable.
Line 2 creates a set containing the values 8, 9, and 10 and assigns it to the set2 variable.
Line 3 calls the set1.update method, passing set2 as an argument. This causes the ele-
ment of set2 to be added to set1. Notice set2 remains unchanged. The following session
shows another example:
1 >>> myset = set([1, 2, 3]) Enter
2 >>> myset.update('abc') Enter
3 >>> myset Enter
4 {'a', 1, 2, 3, 'c', 'b'}
5 >>>
The statement in line 1 creates a set containing the values 1, 2, and 3. Line 2 calls the
myset.update method, passing the string 'abc' as an argument. This causes the each
character of the string to be added as an element to myset.
You can remove an item from a set with either the remove method or the discard method.
You pass the item that you want to remove as an argument to either method, and that item
is removed from the set. The only difference between the two methods is how they behave
when the specified item is not found in the set. The remove method raises a KeyError
exception, but the discard method does not raise an exception. The following interactive
session demonstrates:
1 >>> myset = set([1, 2, 3, 4, 5]) Enter
2 >>> myset Enter
3 {1, 2, 3, 4, 5}
4 >>> myset.remove(1) Enter
5 >>> myset Enter
6 {2, 3, 4, 5}
7 >>> myset.discard(5) Enter
8 >>> myset Enter
9 {2, 3, 4}
10 >>> myset.discard(99) Enter
11 >>> myset.remove(99) Enter
12 Traceback (most recent call last):
13 File "<pyshell#12>", line 1, in <module>
14 myset.remove(99)
15 KeyError: 99
16 >>>
Line 1 creates a set with the elements 1, 2, 3, 4, and 5. Line 2 displays the contents of the
set, which is shown in line 3. Line 4 calls the remove method to remove the value 1 from the
set. You can see in the output shown in line 6 that the value 1 is no longer in the set. Line 7
calls the discard method to remove the value 5 from the set. You can see in the output in
line 9 that the value 5 is no longer in the set. Line 10 calls the discard method to remove
9.2 Sets 497
the value 99 from the set. The value is not found in the set, but the discard method does
not raise an exception. Line 11 calls the remove method to remove the value 99 from the
set. Because the value is not in the set, a KeyError exception is raised, as shown in lines 12
through 15.
You can clear all the elements of a set by calling the clear method. The following interac-
tive session demonstrates:
1 >>> myset = set([1, 2, 3, 4, 5]) Enter
2 >>> myset Enter
3 {1, 2, 3, 4, 5}
4 >>> myset.clear() Enter
5 >>> myset Enter
6 set()
7 >>>
The statement in line 4 calls the clear method to clear the set. Notice in line 6 that when
we display the contents of an empty set, the interpreter displays set().
In the general format, var is the name of a variable and set is the name of a set. This loop
iterates once for each element in the set. Each time the loop iterates, var is assigned an ele-
ment. The following interactive session demonstrates:
1 >>> myset = set(['a', 'b', 'c']) Enter
2 >>> for val in myset: Enter
3 print(val) Enter Enter
4
5 a
6 c
7 b
8 >>>
Lines 2 through 3 contain a for loop that iterates once for each element of the myset set.
Each time the loop iterates, an element of the set is assigned to the val variable. Line 3
prints the value of the val variable. Lines 5 through 7 show the output of the loop.
The if statement in line 2 determines whether the value 1 is in the myset set. If it is, the
statement in line 3 displays a message.
You can also use the not in operator to determine if a value does not exist in a set, as
demonstrated in the following session:
1 >>> myset = set([1, 2, 3]) Enter
2 >>> if 99 not in myset: Enter
3 print('The value 99 is not in the set.') Enter Enter
4
5 The value 99 is not in the set.
6 >>>
In the general format, set1 and set2 are sets. The method returns a set that contains the
elements of both set1 and set2. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1.union(set2) Enter
4 >>> set3 Enter
5 {1, 2, 3, 4, 5, 6}
6 >>>
The statement in line 3 calls the set1 object’s union method, passing set2 as an argument.
The method returns a set that contains all the elements of set1 and set2 (without dupli-
cates, of course). The resulting set is assigned to the set3 variable.
You can also use the | operator to find the union of two sets. Here is the general format of
an expression using the | operator with two sets:
set1 | set2
In the general format, set1 and set2 are sets. The expression returns a set that contains the
elements of both set1 and set2. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1 | set2 Enter
4 >>> set3 Enter
5 {1, 2, 3, 4, 5, 6}
6 >>>
9.2 Sets 499
In the general format, set1 and set2 are sets. The method returns a set that contains the ele-
ments that are found in both set1 and set2. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1.intersection(set2) Enter
4 >>> set3 Enter
5 {3, 4}
6 >>>
The statement in line 3 calls the set1 object’s intersection method, passing set2 as an
argument. The method returns a set that contains the elements that are found in both set1
and set2. The resulting set is assigned to the set3 variable.
You can also use the & operator to find the intersection of two sets. Here is the general
format of an expression using the & operator with two sets:
set1 & set2
In the general format, set1 and set2 are sets. The expression returns a set that contains the
elements that are found in both set1 and set2. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1 & set2 Enter
4 >>> set3 Enter
5 {3, 4}
6 >>>
In the general format, set1 and set2 are sets. The method returns a set that contains the ele-
ments that are found in set1 but not in set2. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1.difference(set2) Enter
4 >>> set3 Enter
5 {1, 2}
6 >>>
500 Chapter 9 Dictionaries and Sets
You can also use the − operator to find the difference of two sets. Here is the general format
of an expression using the − operator with two sets:
set1 − set2
In the general format, set1 and set2 are sets. The expression returns a set that contains
the elements that are found in set1 but not in set2. The following interactive session
demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1 − set2 Enter
4 >>> set3 Enter
5 {1, 2}
6 >>>
In the general format, set1 and set2 are sets. The method returns a set that contains the
elements that are found in either set1 or set2 but not both sets. The following interactive
session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1.symmetric_difference(set2) Enter
4 >>> set3 Enter
5 {1, 2, 5, 6}
6 >>>
You can also use the ˆ operator to find the symmetric difference of two sets. Here is the
general format of an expression using the ˆ operator with two sets:
set1 ˆ set2
In the general format, set1 and set2 are sets. The expression returns a set that contains the
elements that are found in either set1 or set2, but not both sets. The following interactive
session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([3, 4, 5, 6]) Enter
3 >>> set3 = set1 ˆ set2 Enter
4 >>> set3 Enter
5 {1, 2, 5, 6}
6 >>>
9.2 Sets 501
In this example, set1 contains all the elements of set2, which means that set2 is a subset
of set1. It also means that set1 is a superset of set2. In Python, you can call the issubset
method to determine whether one set is a subset of another. Here is the general format:
set2.issubset(set1)
In the general format, set1 and set2 are sets. The method returns True if set2 is a subset
of set1. Otherwise, it returns False. You can call the issuperset method to determine
whether one set is a superset of another. Here is the general format:
set1.issuperset(set2)
In the general format, set1 and set2 are sets. The method returns True if set1 is a super-
set of set2. Otherwise, it returns False. The following interactive session demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([2, 3]) Enter
3 >>> set2.issubset(set1) Enter
4 True
5 >>> set1.issuperset(set2) Enter
6 True
7 >>>
You can also use the <= operator to determine whether one set is a subset of another and
the >= operator to determine whether one set is a superset of another. Here is the general
format of an expression using the <= operator with two sets:
set2 <= set1
In the general format, set1 and set2 are sets. The expression returns True if set2 is a
subset of set1. Otherwise, it returns False. Here is the general format of an expression
using the >= operator with two sets:
set1 >= set2
In the general format, set1 and set2 are sets. The expression returns True if set1
is a subset of set2. Otherwise, it returns False. The following interactive session
demonstrates:
1 >>> set1 = set([1, 2, 3, 4]) Enter
2 >>> set2 = set([2, 3]) Enter
3 >>> set2 <= set1 Enter
4 True
5 >>> set1 >= set2 Enter
6 True
7 >>> set1 <= set2 Enter
8 False
502 Chapter 9 Dictionaries and Sets
In the Spotlight:
Set Operations
In this section, you will look at Program 9-3, which demonstrates various set operations.
The program creates two sets: one that holds the names of students on the baseball team,
and another that holds the names of students on the basketball team. The program then
performs the following operations:
• It finds the intersection of the sets to display the names of students who play both
sports.
• It finds the union of the sets to display the names of students who play either sport.
• It finds the difference of the baseball and basketball sets to display the names of stu-
dents who play baseball but not basketball.
• It finds the difference of the basketball and baseball (basketball – baseball) sets to
display the names of students who play basketball but not baseball. It also finds the
difference of the baseball and basketball (baseball – basketball) sets to display the
names of students who play baseball but not basketball.
• It finds the symmetric difference of the basketball and baseball sets to display the
names of students who play one sport but not both.
Program Output
The following students are on the baseball team:
Jodi
Aida
Carmen
Alicia
Set Comprehensions
A set comprehension is an expression that reads a sequence of input elements and uses
those input elements to produce a set. Set comprehensions work like list comprehensions,
which were discussed in Chapter 7. In fact, set comprehensions are written just like list
comprehensions, except that a set comprehension is enclosed in curly braces ({}), and list
comprehensions are enclosed in square brackets ([]).
Let’s look at some examples. Suppose we have the following set:
set1 = set([1, 2, 3, 4, 5])
The following statement uses a set comprehension to make a copy of the set:
set2 = {item for item in set1}
Let’s look at another example. The following code creates a set of numbers and then creates
a second set that contains the squares of all the numbers in the first set:
set1 = set([1, 2, 3, 4, 5])
set2 = {item**2 for item in set1}
You can also use an if clause with a set comprehension. For example, suppose a set con-
tains integers and you want to make a second set that contains only the integers from the
first set that are less than 10. The following code shows how this can be done with a set
comprehension:
set1 = set([1, 20, 2, 40, 3, 50])
set2 = {item for item in set1 if item < 10}
After this code executes, set2 will contain the following values:
{1, 2, 3}
Checkpoint
9.16 Are the elements of a set ordered or unordered?
9.17 Does a set allow you to store duplicate elements?
9.18 How do you create an empty set?
9.19 After the following statement executes, what elements will be stored in the
myset set?
myset = set('Jupiter')
Classes and Object-
CHAPTER
10 Oriented Programming
TOPICS
10.1 Procedural and Object-Oriented 10.3 Working with Instances
Programming 10.4 Techniques for Designing Classes
10.2 Classes
There are primarily two methods of programming in use today: procedural and object-
oriented. The earliest programming languages were procedural, meaning a program was
made of one or more procedures. You can think of a procedure simply as a function that
performs a specific task such as gathering input from the user, performing calculations,
reading or writing files, displaying output, and so on. The programs that you have written
so far have been procedural in nature.
Typically, procedures operate on data items that are separate from the procedures. In a
procedural program, the data items are commonly passed from one procedure to another.
As you might imagine, the focus of procedural programming is on the creation of pro-
cedures that operate on the program’s data. The separation of data and the code that
operates on the data can lead to problems, however, as the program becomes larger and
more complex.
For example, suppose you are part of a programming team that has written an extensive
customer database program. The program was initially designed so a customer’s name,
521
522 Chapter 10 Classes and Object-Oriented Programming
address, and phone number were referenced by three variables. Your job was to design
several functions that accept those three variables as arguments and perform operations
on them. The software has been operating successfully for some time, but your team has
been asked to update it by adding several new features. During the revision process, the
senior programmer informs you that the customer’s name, address, and phone number
will no longer be stored in variables. Instead, they will be stored in a list. This means
you will have to modify all of the functions that you have designed so they accept and
work with a list instead of the three variables. Making these extensive modifications
not only is a great deal of work, but also opens the opportunity for errors to appear in
your code.
Whereas procedural programming is centered on creating procedures (functions), object-
oriented programming (OOP) is centered on creating objects. An object is a software
entity that contains both data and procedures. The data contained in an object is known as
the object’s data attributes. An object’s data attributes are simply variables that reference
data. The procedures that an object performs are known as methods. An object’s methods
are functions that perform operations on the object’s data attributes. The object is, con-
ceptually, a self-contained unit that consists of data attributes and methods that operate
on the data attributes. This is illustrated in Figure 10-1.
Object
Data attributes
OOP addresses the problem of code and data separation through encapsulation and data
hiding. Encapsulation refers to the combining of data and code into a single object. Data
hiding refers to an object’s ability to hide its data attributes from code that is outside the
object. Only the object’s methods may directly access and make changes to the object’s data
attributes.
An object typically hides its data, but allows outside code to access its methods. As shown
in Figure 10-2, the object’s methods provide programming statements outside the object
with indirect access to the object’s data attributes.
10.1 Procedural and Object-Oriented Programming 523
Figure 10-2 Code outside the object interacts with the object’s methods
Object
Data attributes
Code
outside the
object
When an object’s data attributes are hidden from outside code, and access to the data attri-
butes is restricted to the object’s methods, the data attributes are protected from accidental
corruption. In addition, the code outside the object does not need to know about the format
or internal structure of the object’s data. The code only needs to interact with the object’s
methods. When a programmer changes the structure of an object’s internal data attributes,
he or she also modifies the object’s methods so they may properly operate on the data. The
way in which outside code interacts with the methods, however, does not change.
Object Reusability
In addition to solving the problems of code and data separation, the use of OOP has also
been encouraged by the trend of object reusability. An object is not a stand-alone program,
but is used by programs that need its services. For example, Sharon is a programmer who
has developed a set of objects for rendering 3D images. She is a math whiz and knows a
lot about computer graphics, so her objects are coded to perform all of the necessary 3D
mathematical operations and handle the computer’s video hardware. Tom, who is writing a
program for an architectural firm, needs his application to display 3D images of buildings.
Because he is working under a tight deadline and does not possess a great deal of knowl-
edge about computer graphics, he can use Sharon’s objects to perform the 3D rendering
(for a small fee, of course!).
As you can see, the data attributes are merely values that define the state in which the
alarm clock is currently. You, the user of the alarm clock object, cannot directly manipu-
late these data attributes because they are private. To change a data attribute’s value, you
must use one of the object’s methods. The following are some of the alarm clock object’s
methods:
• set_time
• set_alarm_time
• set_alarm_on
• set_alarm_off
Each method manipulates one or more of the data attributes. For example, the set_time
method allows you to set the alarm clock’s time. You activate the method by pressing a
button on top of the clock. By using another button, you can activate the set_alarm_time
method.
In addition, another button allows you to execute the set_alarm_on and set_alarm_off
methods. Notice all of these methods can be activated by you, who are outside the alarm
clock. Methods that can be accessed by entities outside the object are known as public
methods.
The alarm clock also has private methods, which are part of the object’s private, internal
workings. External entities (such as you, the user of the alarm clock) do not have direct
access to the alarm clock’s private methods. The object is designed to execute these methods
automatically and hide the details from you. The following are the alarm clock object’s
private methods:
• increment_current_second
• increment_current_minute
• increment_current_hour
• sound_alarm
Every second the increment_current_second method executes. This changes the value
of the current_second data attribute. If the current_second data attribute is set to
59 when this method executes, the method is programmed to reset current_second
to 0, and then cause the increment_current_minute method to execute. This method
adds 1 to the current_minute data attribute, unless it is set to 59. In that case, it resets
urrent_minute to 0 and causes the increment_current_hour method to execute. The
c
increment_current_minute method compares the new time to the alarm_time. If the
two times match and the alarm is turned on, the sound_alarm method is executed.
Checkpoint
10.1 What is an object?
10.2 What is encapsulation?
10.3 Why is an object’s internal data usually hidden from outside code?
10.4 What are public methods? What are private methods?
10.2 Classes 525
10.2 Classes
CONCEPT: A class is code that specifies the data attributes and methods for a
particular type of object.
Now, let’s discuss how objects are created in software. Before an object can be created, it
must be designed by a programmer. The programmer determines the data attributes and
VideoNote
Classes and methods that are necessary, then creates a class. A class is code that specifies the data
Objects
attributes and methods of a particular type of object. Think of a class as a “blueprint”
from which objects may be created. It serves a similar purpose as the blueprint for a house.
The blueprint itself is not a house, but is a detailed description of a house. When we use
the blueprint to build an actual house, we could say we are building an instance of the
house described by the blueprint. If we so desire, we can build several identical houses
from the same blueprint. Each house is a separate instance of the house described by the
blueprint. This idea is illustrated in Figure 10-3.
Another way of thinking about the difference between a class and an object is to think of
the difference between a cookie cutter and a cookie. While a cookie cutter itself is not a
cookie, it describes a cookie. The cookie cutter can be used to make one cookie, or several
cookies. Think of a class as a cookie cutter, and the objects created from the class as
cookies.
So, a class is a description of an object’s characteristics. When the program is running, it
can use the class to create, in memory, as many objects of a specific type as needed. Each
object that is created from a class is called an instance of the class.
526 Chapter 10 Classes and Object-Oriented Programming
For example, Jessica is an entomologist (someone who studies insects), and she also enjoys
writing computer programs. She designs a program to catalog different types of insects. As
part of the program, she creates a class named Insect, which specifies characteristics that
are common to all types of insects. The Insect class is a specification from which objects
may be created. Next, she writes programming statements that create an object named
housefly, which is an instance of the Insect class. The housefly object is an entity that
occupies computer memory and stores data about a housefly. It has the data attributes and
methods specified by the Insect class. Then she writes programming statements that create
an object named mosquito. The mosquito object is also an instance of the Insect class.
It has its own area in memory and stores data about a mosquito. Although the housefly
and mosquito objects are separate entities in the computer’s memory, they were both cre-
ated from the Insect class. This means that each of the objects has the data attributes and
methods described by the Insect class. This is illustrated in Figure 10-4.
Figure 10-4 The housefly and mosquito objects are instances of the Insect class
Class Definitions
To create a class, you write a class definition. A class definition is a set of statements that
define a class’s methods and data attributes. Let’s look at a simple example. Suppose we are
writing a program to simulate the tossing of a coin. In the program, we need to repeatedly
toss the coin and each time determine whether it landed heads up or tails up. Taking an
object-oriented approach, we will write a class named Coin that can perform the behaviors
of the coin.
Program 10-1 shows the class definition, which we will explain shortly. Note this is not a
complete program. We will add to it as we go along.
1 import random
2
3 # The Coin class simulates a coin that can
4 # be flipped.
5
6 class Coin:
7
8 # The _ _init_ _ method initializes the
10.2 Classes 527
In line 1, we import the random module. This is necessary because we use the randint
function to generate a random number. Line 6 is the beginning of the class definition. It
begins with the keyword class, followed by the class name, which is Coin, followed by
a colon.
The same rules that apply to variable names also apply to class names. However, notice
that we started the class name, Coin, with an uppercase letter. This is not a requirement,
but it is a widely used convention among programmers. This helps to easily distinguish class
names from variable names when reading code.
The Coin class has three methods:
• The _ _init_ _ method appears in lines 11 through 12.
• The toss method appears in lines 19 through 23.
• The get_sideup method appears in lines 28 through 29.
Except for the fact that they appear inside a class, notice these method definitions look like
any other function definition in Python. They start with a header line, which is followed by
an indented block of statements.
Take a closer look at the header for each of the method definitions (lines 11, 19, and 28)
and notice each method has a parameter variable named self:
Line 11: def _ _init_ _(self):
Line 19: def toss(self):
Line 28: def get_sideup(self):
528 Chapter 10 Classes and Object-Oriented Programming
The self parameter1 is required in every method of a class. Recall from our earlier discus-
sion on object-oriented programming that a method operates on a specific object’s data
attributes. When a method executes, it must have a way of knowing which object’s data
attributes it is supposed to operate on. That’s where the self parameter comes in. When
a method is called, Python makes the self parameter reference the specific object that the
method is supposed to operate on.
Let’s look at each of the methods. The first method, which is named _ _init_ _, is defined
in lines 11 through 12:
def _ _init_ _(self):
self.sideup = 'Heads'
Most Python classes have a special method named _ _init_ _, which is automatically
executed when an instance of the class is created in memory. The _ _init_ _ method is
commonly known as an initializer method because it initializes the object’s data attributes.
(The name of the method starts with two underscore characters, followed by the word
init, followed by two more underscore characters.)
Immediately after an object is created in memory, the _ _init_ _ method executes, and
the self parameter is automatically assigned the object that was just created. Inside the
method, the statement in line 12 executes:
self.sideup = 'Heads'
This statement assigns the string 'Heads' to the sideup data attribute belonging to
the object that was just created. As a result of this _ _init_ _ method, each object we
create from the Coin class will initially have a sideup attribute that is set to 'Heads'.
NOTE: The _ _init_ _ method is usually the first method inside a class definition.
This method also has the required self parameter variable. When the toss method is
called, self will automatically reference the object on which the method is to operate.
The toss method simulates the tossing of the coin. When the method is called, the if
statement in line 20 calls the random.randint function to get a random integer in the
range of 0 through 1. If the number is 0, then the statement in line 21 assigns 'Heads'
to self.sideup. Otherwise, the statement in line 23 assigns 'Tails' to self.sideup.
1
The parameter must be present in a method. You are not required to name it self, but this is
strongly recommended to conform with standard practice.
10.2 Classes 529
Once again, the method has the required self parameter variable. This method simply
returns the value of self.sideup. We call this method any time we want to know which
side of the coin is facing up.
To demonstrate the Coin class, we need to write a complete program that uses it to create
an object. Program 10-2 shows an example. The Coin class definition appears in lines 6
through 29. The program has a main function, which appears in lines 32 through 44.
1 import random
2
3 # The Coin class simulates a coin that can
4 # be flipped.
5
6 class Coin:
7
8 # The _ _init_ _ method initializes the
9 # sideup data attribute with 'Heads'.
10
11 def _ _init_ _(self):
12 self.sideup = 'Heads'
13
14 # The toss method generates a random number
15 # in the range of 0 through 1. If the number
16 # is 0, then sideup is set to 'Heads'.
17 # Otherwise, sideup is set to 'Tails'.
18
19 def toss(self):
20 if random.randint(0, 1) == 0:
21 self.sideup = 'Heads'
22 else:
23 self.sideup = 'Tails'
24
25 # The get_sideup method returns the value
26 # referenced by sideup.
27
28 def get_sideup(self):
29 return self.sideup
30
31 # The main function.
32 def main():
33 # Create an object from the Coin class.
(program continues)
530 Chapter 10 Classes and Object-Oriented Programming
34 my_coin = Coin()
35
36 # Display the side of the coin that is facing up.
37 print('This side is up:', my_coin.get_sideup())
38
39 # Toss the coin.
40 print('I am tossing the coin ...')
41 my_coin.toss()
42
43 # Display the side of the coin that is facing up.
44 print('This side is up:', my_coin.get_sideup())
45
46 # Call the main function.
47 47 if _ _name_ _ == '_ _main_ _':
48 main()
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Tails
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Heads
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Tails
The expression Coin() that appears on the right side of the = operator causes two things
to happen:
1. An object is created in memory from the Coin class.
2. The Coin class’s _ _init_ _ method is executed, and the self parameter is automati-
cally set to the object that was just created. As a result, that object’s sideup attribute
is assigned the string 'Heads'.
Figure 10-5 illustrates these steps.
10.2 Classes 531
A Coin object
After these steps take place,
a Coin object will exist with its sideup 'Heads'
sideup attribute set to 'Heads'.
After this, the = operator assigns the Coin object that was just created to the my_coin
variable. Figure 10-6 shows that after the statement in line 12 executes, the my_coin
variable will reference a Coin object, and that object’s sideup attribute will be assigned
the string 'Heads'.
A Coin object
This statement prints a message indicating the side of the coin that is facing up. Notice
the following expression appears in the statement:
my_coin.get_sideup()
This expression uses the object referenced by my_coin to call the get_sideup method.
When the method executes, the self parameter will reference the my_coin object. As a
result, the method returns the string 'Heads'.
Notice we did not have to pass an argument to the sideup method, despite the fact that
it has the self parameter variable. When a method is called, Python automatically passes
a reference to the calling object into the method’s first parameter. As a result, the self
parameter will automatically reference the object on which the method is to operate.
532 Chapter 10 Classes and Object-Oriented Programming
The statement in line 41 uses the object referenced by my_coin to call the toss method.
When the method executes, the self parameter will reference the my_coin object. The
method will randomly generate a number, then use that number to change the value of the
object’s sideup attribute.
Line 44 executes next. This statement calls my_coin.get_sideup() to display the side of
the coin that is facing up.
Hiding Attributes
Earlier in this chapter, we mentioned that an object’s data attributes should be private,
so that only the object’s methods can directly access them. This protects the object’s data
attributes from accidental corruption. However, in the Coin class that was shown in the
previous example, the sideup attribute is not private. It can be directly accessed by state-
ments that are not in a Coin class method. Program 10-3 shows an example. Note lines 1
through 30 are not shown to conserve space. Those lines contain the Coin class, and they
are the same as lines 1 through 30 in Program 10-2.
Lines 1 through 30 are omitted. These lines are the same as lines 1 through 30 in Program 10-2.
31 # The main function.
32 def main():
33 # Create an object from the Coin class.
34 my_coin = Coin()
35
36 # Display the side of the coin that is facing up.
37 print('This side is up:', my_coin.get_sideup())
38
39 # Toss the coin.
40 print('I am tossing the coin ...')
41 my_coin.toss()
42
43 # But now I'm going to cheat! I'm going to
44 # directly change the value of the object's
45 # sideup attribute to 'Heads'.
46 my_coin.sideup = 'Heads'
47
48 # Display the side of the coin that is facing up.
49 print('This side is up:', my_coin.get_sideup())
50
51 # Call the main function.
52 if _ _name_ _ == '_ _main_ _':
53 main()
10.2 Classes 533
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Heads
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Heads
Program Output
This side is up: Heads
I am tossing the coin ...
This side is up: Heads
Line 34 creates a Coin object in memory and assigns it to the my_coin variable. The state-
ment in line 37 displays the side of the coin that is facing up, then line 41 calls the object’s
toss method. Then, the statement in line 46 directly assigns the string 'Heads' to the obj
ect’s sideup attribute:
my_coin.sideup = 'Heads'
Regardless of the outcome of the toss method, this statement will change the my_coin
object’s sideup attribute to 'Heads'. As you can see from the three sample runs of the
program, the coin always lands heads up!
If we truly want to simulate a coin that is being tossed, then we don’t want code outside the
class to be able to change the result of the toss method. To prevent this from happening,
we need to make the sideup attribute private. In Python, you can hide an attribute by start-
ing its name with two underscore characters. If we change the name of the sideup attribute
to _ _sideup, then code outside the Coin class will not be able to access it. Program 10-4
shows a new version of the Coin class, with this change made.
1 import random
2
3 # The Coin class simulates a coin that can
4 # be flipped.
5
6 class Coin:
7
8 # The _ _init_ _ method initializes the
9 # _ _sideup data attribute with ‘Heads’.
10
11 def _ _init_ _(self):
12 self._ _sideup = 'Heads'
13
(program continues)
534 Chapter 10 Classes and Object-Oriented Programming
Program Output
This side is up: Heads
I am going to toss the coin ten times:
Tails
Heads
Heads
Tails
Tails
10.2 Classes 535
Tails
Tails
Tails
Heads
Heads
1 import random
2
3 # The Coin class simulates a coin that can
4 # be flipped.
5
6 class Coin:
7
8 # The _ _init_ _ method initializes the
9 # _ _sideup data attribute with 'Heads'.
10
11 def _ _init_ _(self):
12 self._ _sideup = 'Heads'
13
14 # The toss method generates a random number
15 # in the range of 0 through 1. If the number
16 # is 0, then sideup is set to 'Heads'.
17 # Otherwise, sideup is set to 'Tails'.
18
19 def toss(self):
20 if random.randint(0, 1) == 0:
21 self._ _sideup = 'Heads'
22 else:
23 self._ _sideup = 'Tails'
24
25 # The get_sideup method returns the value
(program continues)
536 Chapter 10 Classes and Object-Oriented Programming
26 # referenced by sideup.
27
28 def get_sideup(self):
29 return self._ _sideup
Program Output
This side is up: Heads
I am going to toss the coin ten times:
Tails
Tails
Heads
Tails
Heads
Heads
Tails
Heads
Tails
Tails
10.2 Classes 537
Line 4 imports the coin module. Notice in line 8, we had to qualify the name of the Coin
class by prefixing it with the name of the module, followed by a dot:
my_coin = coin.Coin()
Notice the _ _init_ _ method has two parameter variables: self and bal. The bal param-
eter will accept the account’s starting balance as an argument. In line 10, the bal parameter
amount is assigned to the object’s _ _balance attribute.
538 Chapter 10 Classes and Object-Oriented Programming
The deposit method is in lines 15 through 16. This method has two parameter variables:
self and amount. When the method is called, the amount that is to be deposited into the
account is passed into the amount parameter. The value of the parameter is then added to
the _ _balance attribute in line 16.
The withdraw method is in lines 21 through 25. This method has two parameter variables:
self and amount. When the method is called, the amount that is to be withdrawn from
the account is passed into the amount parameter. The if statement that begins in line 22
determines whether there is enough in the account balance to make the withdrawal. If so,
amount is subtracted from _ _balance in line 23. Otherwise, line 25 displays the message
'Error: Insufficient funds'.
The get_balance method is in lines 30 through 31. This method returns the value of the
_ _balance attribute.
Line 7 gets the starting account balance from the user and assigns it to the start_bal vari-
able. Line 10 creates an instance of the BankAccount class and assigns it to the savings
variable. Take a closer look at the statement:
savings = bankaccount.BankAccount(start_bal)
Notice the start_bal variable is listed inside the parentheses. This causes the start_bal
variable to be passed as an argument to the _ _init_ _ method. In the _ _init_ _ method, it
will be passed into the bal parameter.
Line 13 gets the amount of the user’s pay and assigns it to the pay variable. In line 15,
the savings.deposit method is called, passing the pay variable as an argument. In the
deposit method, it will be passed into the amount parameter.
The statement in line 18 displays the account balance. Notice that we are using an f-string
to call the savings.get_balance method. The value that is returned from the method is
formatted to appear as a dollar amount.
Line 21 gets the amount that the user wants to withdraw and assigns it to the cash vari-
able. In line 23 the savings.withdraw method is called, passing the cash variable as
an argument. In the withdraw method, it will be passed into the amount parameter. The
statement in line 26 displays the ending account balance.
_ _balance attribute represents the object’s state at that moment. The following might be
an example of code that displays a BankAccount object’s state:
account = bankaccount.BankAccount(1500.0)
print(f'The balance is ${savings.get_balance():,.2f}'))
The first statement creates a BankAccount object, passing the value 1500.0 to the
_ _init_ _ method. After this statement executes, the account variable will reference the
BankAccount object. The second line displays a formatted string showing the value of
the object’s _ _balance attribute. The output of this statement will look like this:
The balance is $1,500.00
You do not directly call the _ _str_ _ method. Instead, it is automatically called when you
pass an object as an argument to the print function. Program 10-10 shows an example.
The name of the object, savings, is passed to the print function in lines 19 and 27. This
causes the BankAccount class’s _ _str_ _ method to be called. The string that is returned
from the _ _str_ _ method is then displayed.
The _ _str_ _ method is also called automatically when an object is passed as an argument
to the built-in str function. Here is an example:
account = bankaccount2.BankAccount(1500.0)
message = str(account)
print(message)
In the second statement, the account object is passed as an argument to the str function.
This causes the BankAccount class’s _ _str_ _ method to be called. The string that is returned
is assigned to the message variable then displayed by the print function in the third line.
Checkpoint
10.5 You hear someone make the following comment: “A blueprint is a design for
a house. A carpenter can use the blueprint to build the house. If the carpenter
wishes, he or she can build several identical houses from the same blueprint.”
Think of this as a metaphor for classes and objects. Does the blueprint represent
a class, or does it represent an object?
10.6 In this chapter, we use the metaphor of a cookie cutter and cookies that are
made from the cookie cutter to describe classes and objects. In this metaphor, are
objects the cookie cutter, or the cookies?
10.7 What is the purpose of the _ _init_ _ method? When does it execute?
10.8 What is the purpose of the self parameter in a method?
10.9 In a Python class, how do you hide an attribute from code outside the class?
10.10 What is the purpose of the _ _str_ _ method?
10.11 How do you call the _ _str_ _ method?
CONCEPT: Each instance of a class has its own set of data attributes.
When a method uses the self parameter to create an attribute, the attribute belongs to the
specific object that self references. We call these attributes instance attributes because they
belong to a specific instance of the class.
It is possible to create many instances of the same class in a program. Each instance will
then have its own set of attributes. For example, look at Program 10-11. This program
creates three instances of the Coin class. Each instance has its own _ _sideup attribute.
10.3 Working with Instances 543
Program Output
I have three coins with these sides up:
Heads
Heads
Heads
In lines 8 through 10, the following statements create three objects, each an instance of the
Coin class:
coin1 = coin.Coin()
coin2 = coin.Coin()
coin3 = coin.Coin()
Figure 10-7 illustrates how the coin1, coin2, and coin3 variables reference the three
objects after these statements execute. Notice each object has its own _ _sideup attribute.
Lines 14 through 16 display the values returned from each object’s get_sideup method.
Figure 10-7 The coin1, coin2, and coin3 variables reference three Coin objects
A Coin object
A Coin object
A Coin object
Then, the statements in lines 22 through 24 call each object’s toss method:
coin1.toss()
coin2.toss()
coin3.toss()
Figure 10-8 shows how these statements changed each object’s _ _sideup attribute in the
program’s sample run.
A Coin object
A Coin object
In the Spotlight:
Creating the CellPhone Class
Wireless Solutions, Inc. is a business that sells cell phones and wireless service. You are a
programmer in the company’s IT department, and your team is designing a program to
manage all of the cell phones that are in inventory. You have been asked to design a class
that represents a cell phone. The data that should be kept as attributes in the class are as
follows:
• The name of the phone’s manufacturer will be assigned to the _ _manufact attribute.
• The phone’s model number will be assigned to the _ _model attribute.
• The phone’s retail price will be assigned to the _ _retail_price attribute.
The class will also have the following methods:
• An _ _init_ _ method that accepts arguments for the manufacturer, model number,
and retail price.
• A set_manufact method that accepts an argument for the manufacturer. This method
will allow us to change the value of the _ _manufact attribute after the object has
been created, if necessary.
• A set_model method that accepts an argument for the model. This method will allow
us to change the value of the _ _model attribute after the object has been created, if
necessary.
• A set_retail_price method that accepts an argument for the retail price. This
method will allow us to change the value of the _ _retail_price attribute after the
object has been created, if necessary.
• A get_manufact method that returns the phone’s manufacturer.
• A get_model method that returns the phone’s model number.
• A get_retail_price method that returns the phone’s retail price.
Program 10-12 shows the class definition. The class is stored in a module named cellphone.
17
18 # The set_model method accepts an argument for
19 # the phone's model number.
20
21 def set_model(self, model):
22 self._ _model = model
23
24 # The set_retail_price method accepts an argument
25 # for the phone's retail price.
26
27 def set_retail_price(self, price):
28 self._ _retail_price = price
29
30 # The get_manufact method returns the
31 # phone's manufacturer.
32
33 def get_manufact(self):
34 return self._ _manufact
35
36 # The get_model method returns the
37 # phone's model number.
38
39 def get_model(self):
40 return self._ _model
41
42 # The get_retail_price method returns the
43 # phone's retail price.
44
45 def get_retail_price(self):
46 return self._ _retail_price
The CellPhone class will be imported into several programs that your team is develop-
ing. To test the class, you write the code in Program 10-13. This is a simple program that
prompts the user for the phone’s manufacturer, model number, and retail price. An instance
of the CellPhone class is created, and the data is assigned to its attributes.
A method that stores a value in a data attribute or changes the value of a data attribute
in some other way is known as a mutator method. Mutator methods can control the way
that a class’s data attributes are modified. When code outside the class needs to change
the value of an object’s data attribute, it typically calls a mutator and passes the new
value as an argument. If necessary, the mutator can validate the value before it assigns it to
the data attribute. In Program 10-12, the set_manufact, set_model, and set_retail_
price methods are mutator methods.
NOTE: Mutator methods are sometimes called “setters,” and accessor methods are
sometimes called “getters.”
548 Chapter 10 Classes and Object-Oriented Programming
In the Spotlight:
Storing Objects in a List
The CellPhone class you created in the previous In the Spotlight section will be used in a
variety of programs. Many of these programs will store CellPhone objects in lists. To test
the ability to store CellPhone objects in a list, you write the code in Program 10-14. This
program gets the data for five phones from the user, creates five CellPhone objects hold-
ing that data, and stores those objects in a list. It then iterates over the list displaying the
attributes of each object.
38
39 # Return the list.
40 return phone_list
41
42 # The display_list function accepts a list containing
43 # CellPhone objects as an argument and displays the
44 # data stored in each object.
45
46 def display_list(phone_list):
47 for item in phone_list:
48 print(item.get_manufact())
49 print(item.get_model())
50 print(item.get_retail_price())
51 print()
52
53 # Call the main function.
54 if _ _name_ _ == '_ _main_ _':
55 main()
Phone number 1:
Enter the manufacturer: Acme Electronics Enter
Enter the model number: M1000 Enter
Enter the retail price: 199.99 Enter
Phone number 2:
Enter the manufacturer: Atlantic Communications Enter
Enter the model number: S2 Enter
Enter the retail price: 149.99 Enter
Phone number 3:
Enter the manufacturer: Wavelength Electronics Enter
Enter the model number: N477 Enter
Enter the retail price: 249.99 Enter
Phone number 4:
Enter the manufacturer: Edison Wireless Enter
Enter the model number: SLX88 Enter
Enter the retail price: 169.99 Enter
Phone number 5:
Enter the manufacturer: Sonic Systems Enter
Enter the model number: X99 Enter
Enter the retail price: 299.99 Enter
Wavelength Electronics
N477
249.99
Edison Wireless
SLX88
169.99
Sonic Systems
X99
299.99
The make_list function appears in lines 18 through 40. In line 20, an empty list named
phone_list is created. The for loop, which begins in line 24, iterates five times. Each time
the loop iterates, it gets the data for a cell phone from the user (lines 27 through 29), it
creates an instance of the CellPhone class that is initialized with the data (line 34), and it
appends the object to the phone_list list (line 37). Line 40 returns the list.
The display_list function in lines 46 through 51 accepts a list of CellPhone objects as
an argument. The for loop that begins in line 47 iterates over the objects in the list, and
displays the values of each object’s attributes.
The following code sample shows how we might create a Coin object, then pass it as an
argument to the show_coin_status function:
my_coin = coin.Coin()
show_coin_status(my_coin)
When you pass a object as an argument, the thing that is passed into the parameter variable
is a reference to the object. As a result, the function or method that receives the object as an
argument has access to the actual object. For example, look at the following flip method:
def flip(coin_obj):
coin_obj.toss()
This method accepts a Coin object as an argument, and it calls the object’s toss method.
Program 10-15 demonstrates the method.
10.3 Working with Instances 551
Program Output
Heads
Tails
Program Output
Heads
Heads
Program Output
Heads
Tails
The statement in line 8 creates a Coin object, referenced by the variable my_coin.
Line 11 displays the value of the my_coin object’s _ _sideup attribute. Because the object’s
_ _init_ _ method set the _ _sideup attribute to 'Heads', we know that line 11 will dis-
play the string 'Heads'. Line 14 calls the flip function, passing the my_coin object as
an argument. Inside the flip function, the my_coin object’s toss method is called. Then,
line 18 displays the value of the my_coin object’s _ _sideup attribute again. This time,
we cannot predict whether 'Heads' or 'Tails' will be displayed because the my_coin
object’s toss method has been called.
552 Chapter 10 Classes and Object-Oriented Programming
In the Spotlight:
Pickling Your Own Objects
Recall from Chapter 9 that the pickle module provides functions for serializing objects.
Serializing an object means converting it to a stream of bytes that can be saved to a file for
later retrieval. The pickle module’s dump function serializes (pickles) an object and writes it
to a file, and the load function retrieves an object from a file and deserializes (unpickles) it.
In Chapter 9, you saw examples in which dictionary objects were pickled and unpickled.
You can also pickle and unpickle objects of your own classes. Program 10-16 shows an
example that pickles three CellPhone objects and saves them to a file. Program 10-17
retrieves those objects from the file and unpickles them.
34
35 # Call the main function.
36 if _ _name_ _ == '_ _main_ _':
37 main()
Program Output
Manufacturer: ACME Electronics
Model Number: M1000
Retail Price: $199.99
In the Spotlight:
Storing Objects in a Dictionary
Recall from Chapter 9 that dictionaries are objects that store elements as key-value pairs.
Each element in a dictionary has a key and a value. If you want to retrieve a specific value
from the dictionary, you do so by specifying its key. In Chapter 9, you saw examples that
stored values such as strings, integers, floating-point numbers, lists, and tuples in dictio-
naries. Dictionaries are also useful for storing objects that you create from your own classes.
Let’s look at an example. Suppose you want to create a program that keeps contact infor-
mation, such as names, phone numbers, and email addresses. You could start by writing a
class such as the Contact class, shown in Program 10-18. An instance of the Contact class
keeps the following data:
• A person’s name is stored in the _ _name attribute.
• A person’s phone number is stored in the _ _phone attribute.
• A person’s email address is stored in the _ _email attribute.
The class has the following methods:
• An _ _init_ _ method that accepts arguments for a person’s name, phone number,
and email address
• A set_name method that sets the _ _name attribute
10.3 Working with Instances 555
Next, you could write a program that keeps Contact objects in a dictionary. Each time
the program creates a Contact object holding a specific person’s data, that object would
be stored as a value in the dictionary, using the person’s name as the key. Then, any time
you need to retrieve a specific person’s data, you would use that person’s name as a key to
retrieve the Contact object from the dictionary.
Program 10-19 shows an example. The program displays a menu that allows the user to
perform any of the following operations:
• Look up a contact in the dictionary
• Add a new contact to the dictionary
• Change an existing contact in the dictionary
• Delete a contact from the dictionary
• Quit the program
Additionally, the program automatically pickles the dictionary and saves it to a file when
the user quits the program. When the program starts, it automatically retrieves and unpick-
les the dictionary from the file. (Recall from Chapter 10 that pickling an object saves it to a
file, and unpickling an object retrieves it from a file.) If the file does not exist, the program
starts with an empty dictionary.
The program is divided into eight functions: main, load_contacts, get_menu_choice,
look_up, add, change, delete, and save_contacts. Rather than presenting the entire
program at once, let’s first examine the beginning part, which includes the import state-
ments, global constants, and the main function.
23
24 # Process menu selections until the user
25 # wants to quit the program.
26 while choice != QUIT:
27 # Get the user's menu choice.
28 choice = get_menu_choice()
29
30 # Process the choice.
31 if choice == LOOK_UP:
32 look_up(mycontacts)
33 elif choice == ADD:
34 add(mycontacts)
35 elif choice == CHANGE:
36 change(mycontacts)
37 elif choice == DELETE:
38 delete(mycontacts)
39
40 # Save the mycontacts dictionary to a file.
41 save_contacts(mycontacts)
42
Line 2 imports the contact module, which contains the Contact class. Line 3 imports the
pickle module. The global constants that are initialized in lines 6 through 10 are used to
test the user’s menu selection. The FILENAME constant that is initialized in line 13 holds the
name of the file that will contain the pickled copy of the dictionary, which is contacts.dat.
Inside the main function, line 19 calls the load_contacts function. Keep in mind that if
the program has been run before and names were added to the dictionary, those names
have been saved to the contacts.dat file. The load_contacts function opens the file,
gets the dictionary from it, and returns a reference to the dictionary. If the program has not
been run before, the contacts.dat file does not exist. In that case, the load_contacts
function creates an empty dictionary and returns a reference to it. So, after the statement in
line 19 executes, the mycontacts variable references a dictionary. If the program has been
run before, mycontacts references a dictionary containing Contact objects. If this is the
first time the program has run, mycontacts references an empty dictionary.
Line 22 initializes the choice variable with the value 0. This variable will hold the user’s
menu selection.
The while loop that begins in line 26 repeats until the user chooses to quit the program.
Inside the loop, line 28 calls the get_menu_choice function. The get_menu_choice func-
tion displays the following menu:
1. Look up a contact
2. Add a new contact
3. Change an existing contact
4. Delete a contact
5. Quit the program
558 Chapter 10 Classes and Object-Oriented Programming
The user’s selection is returned from the get_menu_choice function and is assigned to the
choice variable.
The if-elif statement in lines 31 through 38 processes the user’s menu choice. If the user
selects item 1, line 32 calls the look_up function. If the user selects item 2, line 34 calls the
add function. If the user selects item 3, line 36 calls the change function. If the user selects
item 4, line 38 calls the delete function.
When the user selects item 5 from the menu, the while loop stops repeating, and the
statement in line 41 executes. This statement calls the save_contacts function, passing
mycontacts as an argument. The save_contacts function saves the mycontacts dictio
nary to the contacts.dat file.
The load_contacts function is next.
43 def load_contacts():
44 try:
45 # Open the contacts.dat file.
46 input_file = open(FILENAME, 'rb')
47
48 # Unpickle the dictionary.
49 contact_dct = pickle.load(input_file)
50
51 # Close the phone_inventory.dat file.
52 input_file.close()
53 except IOError:
54 # Could not open the file, so create
55 # an empty dictionary.
56 contact_dct = {}
57
58 # Return the dictionary.
59 return contact_dct
60
Inside the try suite, line 46 attempts to open the contacts.dat file. If the file is successfully
opened, line 49 loads the dictionary object from it, unpickles it, and assigns it to the con-
tact_dct variable. Line 52 closes the file.
If the contacts.dat file does not exist (this will be the case the first time the program
runs), the statement in line 46 raises an IOError exception. That causes the program to
jump to the except clause in line 53. Then, the statement in line 56 creates an empty dic-
tionary and assigns it to the contact_dct variable.
The statement in line 59 returns the contact_dct variable.
The get_menu_choice function is next.
10.3 Working with Instances 559
The statements in lines 64 through 72 display the menu on the screen. Line 75 prompts
the user to enter his or her choice. The input is converted to an int and assigned to the
choice variable. The while loop in lines 78 through 79 validates the user’s input and, if
necessary, prompts the user to reenter his or her choice. Once a valid choice is entered, it
is returned from the function in line 82.
The look_up function is next.
The purpose of the look_up function is to allow the user to look up a specified contact.
It accepts the mycontacts dictionary as an argument. Line 88 prompts the user to enter a
name, and line 91 passes that name as an argument to the dictionary’s get function. One of
the following actions will happen as a result of line 91:
• If the specified name is found as a key in the dictionary, the get method returns a
reference to the Contact object that is associated with that name. The Contact object
is then passed as an argument to the print function. The print function displays the
string that is returned from the Contact object’s _ _str_ _ method.
• If the specified name is not found as a key in the dictionary, the get method returns
the string 'That name is not found.', which is displayed by the print function.
The add function is next.
The purpose of the add function is to allow the user to add a new contact to the dictionary.
It accepts the mycontacts dictionary as an argument. Lines 97 through 99 prompt the user
to enter a name, a phone number, and an email address. Line 102 creates a new Contact
object, initialized with the data entered by the user.
The if statement in line 107 determines whether the name is already in the dictionary. If
not, line 108 adds the newly created Contact object to the dictionary, and line 109 prints
a message indicating that the new data is added. Otherwise, a message indicating that the
entry already exists is printed in line 111.
The change function is next.
10.3 Working with Instances 561
The purpose of the change function is to allow the user to change an existing contact in
the dictionary. It accepts the mycontacts dictionary as an argument. Line 117 gets a name
from the user. The if statement in line 119 determines whether the name is in the dictio-
nary. If so, line 121 gets the new phone number, and line 124 gets the new email address.
Line 127 creates a new Contact object initialized with the existing name and the new
phone number and email address. Line 130 stores the new Contact object in the dictio-
nary, using the existing name as the key.
If the specified name is not in the dictionary, line 133 prints a message indicating so.
The delete function is next.
The purpose of the delete function is to allow the user to delete an existing contact from
the dictionary. It accepts the mycontacts dictionary as an argument. Line 139 gets a name
from the user. The if statement in line 142 determines whether the name is in the dictio-
nary. If so, line 143 deletes it, and line 144 prints a message indicating that the entry was
deleted. If the name is not in the dictionary, line 146 prints a message indicating so.
The save_contacts function is next.
The save_contacts function is called just before the program stops running. It accepts the
mycontacts dictionary as an argument. Line 152 opens the contacts.dat file for writing.
Line 155 pickles the mycontacts dictionary and saves it to the file. Line 158 closes the file.
The following program output shows two sessions with the program. The sample output
does not demonstrate everything the program can do, but it does demonstrate how contacts
are saved when the program ends and then loaded when the program runs again.
Menu
---------------------------
1. Look up a contact
2. Add a new contact
3. Change an existing contact
4. Delete a contact
5. Quit the program
Menu
---------------------------
1. Look up a contact
2. Add a new contact
3. Change an existing contact
4. Delete a contact
5. Quit the program
Menu
---------------------------
1. Look up a contact
2. Add a new contact
3. Change an existing contact
4. Delete a contact
5. Quit the program
Checkpoint
10.12 What is an instance attribute?
10.13 A program creates 10 instances of the Coin class. How many _ _sideup
attributes exist in memory?
10.14 What is an accessor method? What is a mutator method?
Following this layout, Figure 10-10 and 10-11 show UML diagrams for the Coin class and
the CellPhone class that you saw previously in this chapter. Notice we did not show the
self parameter in any of the methods, since it is understood that the self parameter is
required.
Coin
__sideup
__init__( )
toss( )
get_sideup( )
CellPhone
__manufact
__model
__retail_price
__init__(manufact, model, price)
set_manufact(manufact)
set_model(model)
set_retail_price(price)
get_manufact()
get_model()
get_retail_price()
Notice some of the nouns are repeated. The following list shows all of the nouns without
duplicating any of them:
address
BMW
car
cars
customer
estimated labor charges
estimated parts charges
foreign cars
Joe’s Automotive Shop
make
manager
Mercedes
model
10.4 Techniques for Designing Classes 567
name
Porsche
sales tax
service quote
shop
telephone number
total estimated charges
year
address
BMW
car
cars
customer Because car, cars, and foreign cars mean
estimated labor charges the same thing in this problem, we have
eliminated cars and foreign cars. Also,
estimated parts charges
because Joe’s Automotive Shop and shop
foreign cars mean the same thing, we have eliminated
Joe’s Automotive Shop Joe’s Automotive Shop.
make
manager
Mercedes
model
name
Porsche
sales tax
service quote
(continued)
568 Chapter 10 Classes and Object-Oriented Programming
shop
telephone number
total estimated charges
year
2. Some nouns might represent items that we do not need to be concerned with in order
to solve the problem.
A quick review of the problem description reminds us of what our application should do:
print a service quote. In this example, we can eliminate two unnecessary classes from the list:
• We can cross shop off the list because our application only needs to be concerned with
individual service quotes. It doesn’t need to work with or determine any company-wide
information. If the problem description asked us to keep a total of all the service quotes,
then it would make sense to have a class for the shop.
• We will not need a class for the manager because the problem statement does not
direct us to process any information about the manager. If there were multiple shop
managers, and the problem description had asked us to record which manager gener-
ated each service quote, then it would make sense to have a class for the manager.
The updated list of potential classes at this point is:
address
BMW
car
cars
customer
estimated labor charges
estimated parts charges
foreign cars
Joe’s Automotive Shop
make
Our problem description does not direct us to
manager process any information about the shop, or any
Mercedes information about the manager, so we have
model eliminated those from the list.
name
Porsche
sales tax
service quote
shop
telephone number
total estimated charges
year
10.4 Techniques for Designing Classes 569
address
BMW
car
cars
customer
estimated labor charges
estimated parts charges
foreign cars We have eliminated Mercedes, Porsche, and
Joe’s Automotive Shop BMW because they are all instances of a car
class. That means that these nouns identify
manager
objects, not classes.
make
Mercedes
model
name
Porsche
sales tax
service quote
shop
telephone number
total estimated charges
year
NOTE: Some object-oriented designers take note of whether a noun is plural or singular.
Sometimes a plural noun will indicate a class, and a singular noun will indicate an object.
4. Some of the nouns might represent simple values that can be assigned to a variable
and do not require a class.
Remember, a class contains data attributes and methods. Data attributes are related items
that are stored in an object of the class and define the object’s state. Methods are actions
or behaviors that can be performed by an object of the class. If a noun represents a type
of item that would not have any identifiable data attributes or methods, then it can prob-
ably be eliminated from the list. To help determine whether a noun represents an item that
would have data attributes and methods, ask the following questions about it:
• Would you use a group of related values to represent the item’s state?
• Are there any obvious actions to be performed by the item?
570 Chapter 10 Classes and Object-Oriented Programming
If the answers to both of these questions are no, then the noun probably represents a value
that can be stored in a simple variable. If we apply this test to each of the nouns that remain
in our list, we can conclude that the following are probably not classes: address, estimated
labor charges, estimated parts charges, make, model, name, sales tax, telephone number,
total estimated charges, and year. These are all simple string or numeric values that can be
stored in variables. Here is the updated list of potential classes:
Address
BMW
car
cars
customer
estimated labor charges We have eliminated address, estimated
estimated parts charges labor charges, estimated parts charges,
make, model, name, sales tax, telephone
foreign cars
number, total estimated charges, and
Joe’s Automotive Shop year as classes because they represent
make simple values that can be stored in
manager variables.
Mercedes
model
name
Porsche
sales tax
service quote
shop
telephone number
total estimated charges
year
As you can see from the list, we have eliminated everything except car, customer, and
service quote. This means that in our application, we will need classes to represent cars,
customers, and service quotes. Ultimately, we will write a Car class, a Customer class, and
a ServiceQuote class.
When you have identified the things that a class is responsible for knowing, then you have
identified the class’s data attributes. Likewise, when you have identified the actions that a
class is responsible for doing, you have identified its methods.
It is often helpful to ask the questions “In the context of this problem, what must the class
know? What must the class do?” The first place to look for the answers is in the descrip-
tion of the problem domain. Many of the things that a class must know and do will be
mentioned. Some class responsibilities, however, might not be directly mentioned in the
problem domain, so further consideration is often required. Let’s apply this methodology
to the classes we previously identified from our problem domain.
Customer
__name
__address
__phone
__init__(name, address,
phone)
set_name(name)
set_address(address)
set_phone(phone)
get_name()
get_address()
get_phone()
572 Chapter 10 Classes and Object-Oriented Programming
1 # Customer class
2 class Customer:
3 def _ _init_ _(self, name, address, phone):
4 self._ _name = name
5 self._ _address = address
6 self._ _phone = phone
7
8 def set_name(self, name):
9 self._ _name = name
10
11 def set_address(self, address):
12 self._ _address = address
13
14 def set_phone(self, phone):
15 self._ _phone = phone
16
17 def get_name(self):
18 return self._ _name
19
20 def get_address(self):
21 return self._ _address
22
23 def get_phone(self):
24 return self._ _phone
Car
__make
__model
__year
__init__(make, model,
year)
set_make(make)
set_model(make)
set_year(y)
get_make( )
get_model( )
get_year( )
1 # Car class
2 class Car:
3 def _ _init_ _(self, make, model, year):
4 self._ _make = make
5 self._ _model = model
6 self._ _year = year
7
8 def set_make(self, make):
9 self._ _make = make
10
11 def set_model(self, model):
12 self._ _model = model
13
14 def set_year(self, year):
15 self._ _year = year
16
17 def get_make(self):
18 return self._ _make
19
20 def get_model(self):
21 return self._ _model
22
23 def get_year(self):
24 return self._ _year
ServiceQuote
__parts_charges
__labor_charges
__init__(pcharge, lcharge)
set_parts_charges(pcharge)
set_labor_charges(lcharge)
get_parts_charges( )
get_labor_charges( )
get_sales_tax( )
get_total_charges( )
25 def get_total_charges(self):
26 return _ _parts_charges + _ _labor_charges + \
27 (_ _parts_charges * TAX_RATE)
Checkpoint
10.15 The typical UML diagram for a class has three sections. What appears in these
three sections?
10.16 What is a problem domain?
10.17 When designing an object-oriented application, who should write a description of
the problem domain?
10.18 How do you identify the potential classes in a problem domain description?
10.19 What are a class’s responsibilities?
10.20 What two questions should you ask to determine a class’s responsibilities?
10.21 Will all of a class’s actions always be directly mentioned in the problem domain
description?
Review Questions
Multiple Choice
1. The ______________ programming practice is centered on creating functions that are
separate from the data that they work on.
a. modular
b. procedural
c. functional
d. object-oriented
2. The ______________ programming practice is centered on creating objects.
a. object-centric
b. objective
c. procedural
d. object-oriented
576 Chapter 10 Classes and Object-Oriented Programming
11. In one approach to identifying the classes in a problem, the programmer identifies the
______________ in a description of the problem domain.
a. verbs
b. adjectives
c. adverbs
d. nouns
12. In one approach to identifying a class’s data attributes and methods, the programmer
identifies the class’s ______________.
a. responsibilities
b. name
c. synonyms
d. nouns
True or False
1. The practice of procedural programming is centered on the creation of objects.
2. Object reusability has been a factor in the increased use of object-oriented programming.
3. It is a common practice in object-oriented programming to make all of a class’s data
attributes accessible to statements outside the class.
4. A class method does not have to have a self parameter.
5. Starting an attribute name with two underscores will hide the attribute from code
outside the class.
6. You cannot directly call the _ _str_ _ method.
7. One way to find the classes needed for an object-oriented program is to identify all of
the verbs in a description of the problem domain.
Short Answer
1. What is encapsulation?
2. Why should an object’s data attributes be hidden from code outside the class?
3. What is the difference between a class and an instance of a class?
4. The following statement calls an object’s method. What is the name of the method?
What is the name of the variable that references the object?
wallet.get_dollar()
5. When the _ _init_ _ method executes, what does the self parameter reference?
6. In a Python class, how do you hide an attribute from code outside the class?
7. How do you call the _ _str_ _ method?
Algorithm Workbench
1. Suppose my_car is the name of a variable that references an object, and go is the name
of a method. Write a statement that uses the my_car variable to call the go method.
(You do not have to pass any arguments to the go method.)
578 Chapter 10 Classes and Object-Oriented Programming
2. Write a class definition named Book. The Book class should have data attributes for a
book’s title, the author’s name, and the publisher’s name. The class should also have
the following:
a. An _ _init_ _ method for the class. The method should accept an argument for
each of the data attributes.
b. Accessor and mutator methods for each data attribute.
c. An _ _str_ _ method that returns a string indicating the state of the object.
3. Look at the following description of a problem domain:
The bank offers the following types of accounts to its customers: savings accounts,
checking accounts, and money market accounts. Customers are allowed to deposit
money into an account (thereby increasing its balance), withdraw money from an
account (thereby decreasing its balance), and earn interest on the account. Each
account has an interest rate.
Assume that you are writing a program that will calculate the amount of interest
earned for a bank account.
a. Identify the potential classes in this problem domain.
b. Refine the list to include only the necessary class or classes for this problem.
c. Identify the responsibilities of the class or classes.
Programming Exercises
1. Pet Class
VideoNote
Write a class named Pet, which should have the following data attributes:
The Pet class
• _ _name (for the name of a pet)
• _ _animal_type (for the type of animal that a pet is. Example values are ‘Dog’, ‘Cat’,
and ‘Bird’)
• _ _age (for the pet’s age)
The Pet class should have an _ _init_ _ method that creates these attributes. It should also
have the following methods:
• set_name
This method assigns a value to the _ _name field.
• set_animal_type
This method assigns a value to the _ _animal_type field.
• set_age
This method assigns a value to the _ _age field.
• get_name
This method returns the value of the _ _ name field.
• get_animal_type
This method returns the value of the _ _animal_type field.
• get_age
This method returns the value of the _ _age field.
Once you have written the class, write a program that creates an object of the class and
prompts the user to enter the name, type, and age of his or her pet. This data should be
Programming Exercises 579
stored as the object’s attributes. Use the object’s accessor methods to retrieve the pet’s
name, type, and age and display this data on the screen.
2. Car Class
Write a class named Car that has the following data attributes:
• _ _year_model (for the car’s year model)
• _ _make (for the make of the car)
• _ _speed (for the car’s current speed)
The Car class should have an _ _init_ _ method that accepts the car’s year model and
make as arguments. These values should be assigned to the object’s _ _year_model and
_ _make data attributes. It should also assign 0 to the _ _speed data attribute.
The class should also have the following methods:
• accelerate
The accelerate method should add 5 to the speed data attribute each time it is called.
• brake
The brake method should subtract 5 from the speed data attribute each time it is called.
• get_speed
The get_speed method should return the current speed.
Next, design a program that creates a Car object then calls the accelerate method five
times. After each call to the accelerate method, get the current speed of the car and dis-
play it. Then call the brake method five times. After each call to the brake method, get the
current speed of the car and display it.
3. Personal Information Class
Design a class that holds the following personal data: name, address, age, and phone num-
ber. Write appropriate accessor and mutator methods. Also, write a program that creates
three instances of the class. One instance should hold your information, and the other two
should hold your friends’ or family members’ information.
4. Employee Class
Write a class named Employee that holds the following data about an employee in attrib-
utes: name, ID number, department, and job title.
Once you have written the class, write a program that creates three Employee objects to
hold the following data:
The program should store this data in the three objects, then display the data for each
employee on the screen.
580 Chapter 10 Classes and Object-Oriented Programming
5. RetailItem Class
Write a class named RetailItem that holds data about an item in a retail store. The class
should store the following data in attributes: item description, units in inventory, and price.
Once you have written the class, write a program that creates three RetailItem objects
and stores the following data in them:
6. Patient Charges
Write a class named Patient that has attributes for the following data:
• First name, middle name, and last name
• Address, city, state, and ZIP code
• Phone number
• Name and phone number of emergency contact
The Patient class’s _ _init_ _ method should accept an argument for each attribute. The
Patient class should also have accessor and mutator methods for each attribute.
Next, write a class named Procedure that represents a medical procedure that has been
performed on a patient. The Procedure class should have attributes for the following data:
• Name of the procedure
• Date of the procedure
• Name of the practitioner who performed the procedure
• Charges for the procedure
The Procedure class’s _ _init_ _ method should accept an argument for each attribute.
The Procedure class should also have accessor and mutator methods for each attribute.
Next, write a program that creates an instance of the Patient class, initialized with sample
data. Then, create three instances of the Procedure class, initialized with the following data:
The program should display the patient’s information, information about all three of the
procedures, and the total charges of the three procedures.
Programming Exercises 581
To create this program, write a Question class to hold the data for a trivia question. The
Question class should have attributes for the following data:
• A trivia question
• Possible answer 1
• Possible answer 2
• Possible answer 3
• Possible answer 4
• The number of the correct answer (1, 2, 3, or 4)
The Question class also should have an appropriate _ _init_ _ method, accessors, and
mutators.
The program should have a list or a dictionary containing 10 Question objects, one for
each trivia question. Make up your own trivia questions on the subject or subjects of your
choice for the objects.
CHAPTER
11 Inheritance
TOPICS
11.1 Introduction to Inheritance
11.2 Polymorphism
CONCEPT: Inheritance allows a new class to extend an existing class. The new class
inherits the members of the class it extends.
583
584 Chapter 11 Inheritance
NOTE: Superclasses are also called base classes, and subclasses are also called derived
classes. Either set of terms is correct. For consistency, this text will use the terms super-
class and subclass.
Let’s look at an example of how inheritance can be used. Suppose we are developing a
program that a car dealership can use to manage its inventory of used cars. The dealer-
ship’s inventory includes three types of automobiles: cars, pickup trucks, and sport-utility
11.1 Introduction to Inheritance 585
vehicles (SUVs). Regardless of the type, the dealership keeps the following data about each
automobile:
• Make
• Year model
• Mileage
• Price
Each type of vehicle that is kept in inventory has these general characteristics, plus its own
specialized characteristics. For cars, the dealership keeps the following additional data:
• Number of doors (2 or 4)
For pickup trucks, the dealership keeps the following additional data:
• Drive type (two-wheel drive or four-wheel drive)
And for SUVs, the dealership keeps the following additional data:
• Passenger capacity
In designing this program, one approach would be to write the following three classes:
• A Car class with data attributes for the make, year model, mileage, price, and the
number of doors.
• A Truck class with data attributes for the make, year model, mileage, price, and the
drive type.
• An SUV class with data attributes for the make, year model, mileage, price, and the
passenger capacity.
This would be an inefficient approach, however, because all three of the classes have a large
number of common data attributes. As a result, the classes would contain a lot of dupli-
cated code. In addition, if we discover later that we need to add more common attributes,
we would have to modify all three classes.
A better approach would be to write an Automobile superclass to hold all the general data
about an automobile, then write subclasses for each specific type of automobile. Program 11-1
shows the Automobile class’s code, which appears in a module named vehicles.
(program continues)
586 Chapter 11 Inheritance
The Automobile class’s _ _init_ _ method accepts arguments for the vehicle’s make,
model, mileage, and price. It uses those values to initialize the following data attributes:
• _ _make
• _ _model
• _ _mileage
• _ _price
(Recall from Chapter 10 that a data attribute becomes hidden when its name begins with
two underscores.) The methods that appear in lines 18 through 28 are mutators for each of
the data attributes, and the methods in lines 33 through 43 are the accessors.
11.1 Introduction to Inheritance 587
The Automobile class is a complete class from which we can create objects. If we wish,
we can write a program that imports the vehicle module and creates instances of the
Automobile class. However, the Automobile class holds only general data about an auto-
mobile. It does not hold any of the specific pieces of data that the dealership wants to keep
about cars, pickup trucks, and SUVs. To hold data about those specific types of automo-
biles, we will write subclasses that inherit from the Automobile class. Program 11-2 shows
the code for the Car class, which is also in the vehicles module.
Take a closer look at the first line of the class declaration, in line 48:
class Car(Automobile):
This line indicates that we are defining a class named Car, and it inherits from the Automobile
class. The Car class is the subclass, and the Automobile class is the superclass. If we want
to express the relationship between the Car class and the Automobile class, we can say that
a Car is an Automobile. Because the Car class extends the Automobile class, it inherits all
of the methods and data attributes of the Automobile class.
588 Chapter 11 Inheritance
Notice in addition to the required self parameter, the method has parameters named make,
model, mileage, price, and doors. This makes sense because a Car object will have data
attributes for the car’s make, model, mileage, price, and number of doors. Some of these
attributes are created by the Automobile class, however, so we need to call the Automobile
class’s _ _init_ _ method and pass those values to it. That happens in line 56:
Automobile._ _init_ _(self, make, model, mileage, price)
This statement calls the Automobile class’s _ _init_ _ method. Notice the statement passes
the self variable, as well as the make, model, mileage, and price variables as arguments.
When that method executes, it initializes the _ _make, _ _model, _ _mileage, and _ _price
data attributes. Then, in line 59, the _ _doors attribute is initialized with the value passed
into the doors parameter:
self._ _doors = doors
The set_doors method, in lines 64 through 65, is the mutator for the _ _doors attribute,
and the get_doors method, in lines 70 through 71, is the accessor for the _ _doors attri-
bute. Before going any further, let’s demonstrate the Car class, as shown in Program 11-3.
Program Output
Make: Audi
Model: 2007
11.1 Introduction to Inheritance 589
Mileage: 12500
Price: 21500.0
Number of doors: 4
Line 3 imports the vehicles module, which contains the class definitions for the
Automobile and Car classes. Line 9 creates an instance of the Car class, passing 'Audi' as
the car’s make, 2007 as the car’s model, 12,500 as the mileage, 21,500.0 as the car’s price,
and 4 as the number of doors. The resulting object is assigned to the used_car variable.
The statements in lines 12 through 15 call the object’s get_make, get_model, get_mileage,
and get_price methods. Even though the Car class does not have any of these methods,
it inherits them from the Automobile class. Line 16 calls the get_doors method, which is
defined in the Car class.
Now let’s look at the Truck class, which also inherits from the Automobile class. The code
for the Truck class, which is also in the vehicles module, is shown in Program 11-4.
The Truck class’s _ _init_ _ method begins in line 80. Notice it takes arguments for the
truck’s make, model, mileage, price, and drive type. Just as the Car class did, the Truck
class calls the Automobile class’s _ _init_ _ method (in line 84) passing the make, model,
mileage, and price as arguments. Line 87 creates the _ _drive_type attribute, initializing
it to the value of the drive_type parameter.
The set_drive_type method in lines 92 through 93 is the mutator for the _ _drive_type
attribute, and the get_drive_type method in lines 98 through 99 is the accessor for the
attribute.
Now let’s look at the SUV class, which also inherits from the Automobile class. The code
for the SUV class, which is also in the vehicles module, is shown in Program 11-5.
The SUV class’s _ _init_ _ method begins in line 109. It takes arguments for the vehicle’s
make, model, mileage, price, and passenger capacity. Just as the Car and Truck classes
did, the SUV class calls the Automobile class’s _ _init_ _ method (in line 113) passing the
11.1 Introduction to Inheritance 591
make, model, mileage, and price as arguments. Line 116 creates the _ _pass_cap attribute,
initializing it to the value of the pass_cap parameter.
The set_pass_cap method in lines 121 through 122 is the mutator for the _ _pass_cap
attribute, and the get_pass_cap method in lines 127 through 128 is the accessor for the
attribute.
Program 11-6 demonstrates each of the classes we have discussed so far. It creates a Car
object, a Truck object, and an SUV object.
37 print('Model:', truck.get_model())
38 print('Mileage:', truck.get_mileage())
39 print('Price:', truck.get_price())
40 print('Drive type:', truck.get_drive_type())
41 print()
42
43 # Display the SUV's data.
44 print('The following SUV is in inventory.')
45 print('Make:', suv.get_make())
46 print('Model:', suv.get_model())
47 print('Mileage:', suv.get_mileage())
48 print('Price:', suv.get_price())
49 print('Passenger Capacity:', suv.get_pass_cap())
50
51 # Call the main function.
52 if _ _name_ _ == '_ _main_ _':
53 main()
Program Output
USED CAR INVENTORY
==================
The following car is in inventory:
Make: BMW
Model: 2001
Mileage: 70000
Price: 15000.0
Number of doors: 4
Automobile
__make
__model
__mileage
__price
__init__(make, model,
mileage, price)
set_make(make)
set_model(model)
set_mileage(mileage)
set_price(price)
get_make( )
get_model( )
get_mileage( )
get_price()
In the Spotlight:
Using Inheritance
Bank Financial Systems, Inc. develops financial software for banks and credit unions. The
company is developing a new object-oriented system that manages customer accounts. One
of your tasks is to develop a class that represents a savings account. The data that must be
held by an object of this class is:
• The account number.
• The interest rate.
• The account balance.
You must also develop a class that represents a certificate of deposit (CD) account. The data
that must be held by an object of this class is:
• The account number.
• The interest rate.
• The account balance.
• The account maturity date.
594 Chapter 11 Inheritance
As you analyze these requirements, you realize that a CD account is really a specialized
version of a savings account. The class that represents a CD will hold all of the same data
as the class that represents a savings account, plus an extra attribute for the maturity date.
You decide to design a SavingsAccount class to represent a savings account, then design
a subclass of SavingsAccount named CD to represent a CD account. You will store both
of these classes in a module named accounts . Program 11-7 shows the code for the
SavingsAccount class.
The class’s _ _init_ _ method appears in lines 9 through 12. The _ _init_ _ method accepts
arguments for the account number, interest rate, and balance. These arguments are used to
initialize data attributes named _ _account_num, _ _interest_rate, and _ _balance.
The set_account_num , set_interest_rate , and set_balance methods that ap-
pear in lines 17 through 24 are mutators for the data attributes. The get_account_num,
get_interest_rate, and get_balance methods that appear in lines 29 through 36 are
accessors.
The CD class is shown in the next part of Program 11-7.
The CD class’s _ _init_ _ method appears in lines 48 through 53. It accepts arguments
for the account number, interest rate, balance, and maturity date. Line 50 calls the
SavingsAccount class’s _ _init_ _ method, passing the arguments for the account number,
interest rate, and balance. After the SavingsAccount class’s _ _init_ _ method executes,
the _ _account_num, _ _interest_rate, and _ _balance attributes will be created and
initialized. Then the statement in line 53 creates the _ _maturity_date attribute.
596 Chapter 11 Inheritance
37 print()
38 print('CD')
39 print('---------------')
40 print(f'Account number: {cd.get_account_num()}')
41 print(f'Interest rate: {cd.get_interest_rate()}')
42 print(f'Balance: ${cd.get_balance():,.2f}')
43 print(f'Maturity date: {cd.get_maturity_date()}')
44
45 # Call the main function.
46 if _ _name_ _ == '_ _main_ _':
47 main()
Savings Account
---------------
Account number: 1234SA
Interest rate: 3.5
Balance: $1,000.00
CD
---------------
Account number: 2345CD
Interest rate: 5.6
Balance: $2,500.00
Maturity date: 12/12/2024
Checkpoint
11.1 In this section, we discussed superclasses and subclasses. Which is the general
class, and which is the specialized class?
11.2 What does it mean to say there is an “is a” relationship between two objects?
11.3 What does a subclass inherit from its superclass?
11.4 Look at the following code, which is the first line of a class definition. What is the
name of the superclass? What is the name of the subclass?
class Canary(Bird):
598 Chapter 11 Inheritance
11.2 Polymorphism
CONCEPT: Polymorphism allows subclasses to have methods with the same names
as methods in their superclasses. It gives the ability for a program to call
the correct method depending on the type of object that is used to call it.
The term polymorphism refers to an object’s ability to take different forms. It is a power-
ful feature of object-oriented programming. In this section, we will look at two essential
ingredients of polymorphic behavior:
1. The ability to define a method in a superclass, then define a method with the same
name in a subclass. When a subclass method has the same name as a superclass
method, it is often said that the subclass method overrides the superclass method.
2. The ability to call the correct version of an overridden method, depending on the
type of object that is used to call it. If a subclass object is used to call an overridden
method, then the subclass’s version of the method is the one that will execute. If a
superclass object is used to call an overridden method, then the superclass’s version
of the method is the one that will execute.
Actually, you’ve already seen method overriding at work. Each subclass that we have exam-
ined in this chapter has a method named _ _init_ _ that overrides the superclass’s _ _init_ _
method. When an instance of the subclass is created, it is the subclass’s _ _init_ _ method
that automatically gets called.
Method overriding works for other class methods too. Perhaps the best way to describe
polymorphism is to demonstrate it, so let’s look at a simple example. Program 11-9 shows
the code for a class named Mammal, which is in a module named animals.
19
20 def make_sound(self):
21 print('Grrrrr')
22
The Mammal class has three methods: _ _init_ _, show_species and make_sound. Here is
an example of code that creates an instance of the class and calls these methods:
import animals
mammal = animals.Mammal('regular mammal')
mammal.show_species()
mammal.make_sound()
The next part of Program 11-9 shows the Dog class. The Dog class, which is also in the
animals module, is a subclass of the Mammal class.
Even though the Dog class inherits the _ _init_ _ and make_sound methods that are in the
Mammal class, those methods are not adequate for the Dog class. So, the Dog class has its
own _ _init_ _ and make_sound methods, which perform actions that are more appropri-
ate for a dog. We say that the _ _init_ _ and make_sound methods in the Dog class override
the _ _init_ _ and make_sound methods in the Mammal class. Here is an example of code
that creates an instance of the Dog class and calls the methods:
import animals
dog = animals.Dog()
600 Chapter 11 Inheritance
dog.show_species()
dog.make_sound()
When we use a Dog object to call the show_species and make_sound methods, the ver-
sions of these methods that are in the Dog class are the ones that execute. Next, look at
Program 11-10, which shows the Cat class. The Cat class, which is also in the animals
module, is another subclass of the Mammal class.
The Cat class also overrides the Mammal class’s _ _init_ _ and make_sound methods. Here
is an example of code that creates an instance of the Cat class and calls these methods:
import animals
cat = animals.Cat()
cat.show_species()
cat.make_sound()
When we use a Cat object to call the show_species and make_sound methods, the ver-
sions of these methods that are in the Cat class are the ones that execute.
11.2 Polymorphism 601
We can pass any object as an argument to this function, and as long as it has a show_
species method and a make_sound method, the function will call those methods. In
essence, we can pass any object that “is a” Mammal (or a subclass of Mammal) to the func-
tion. Program 11-10 demonstrates.
But what happens if we pass an object that is not a Mammal, and not of a subclass of Mammal
to the function? For example, what will happen when Program 11-11 runs?
1 def main():
2 # Pass a string to show_mammal_info …
3 show_mammal_info('I am a string')
4
5 # The show_mammal_info function accepts an object
6 # as an argument, and calls its show_species
7 # and make_sound methods.
8
9 def show_mammal_info(creature):
10 creature.show_species()
11 creature.make_sound()
12
13 # Call the main function.
14 if _ _name_ _ == '_ _main_ _':
15 main()
Program Output
Here are some animals and
the sounds they make.
--------------------------
I am a regular animal
Grrrrr
(program output continues)
604 Chapter 11 Inheritance
In lines 16, 18, and 20 we call the show_mammal_info function, passing references to a
Mammal object, a Dog object, and a Cat object. In line 22, however, we call the function and
pass a string as an argument. Inside the show_mammal_info function, the if statement in
line 29 calls the isinstance function to determine whether the argument is an instance of
Mammal (or a subclass). If it is not, an error message is displayed.
Checkpoint
11.5 Look at the following class definitions:
class Vegetable:
def _ _init_ _(self, vegtype):
self._ _vegtype = vegtype
def message(self):
print("I'm a vegetable.")
class Potato(Vegetable):
def _ _init_ _(self):
Vegetable._ _init_ _(self, 'potato')
def message(self):
print("I'm a potato.")
Given these class definitions, what will the following statements display?
v = Vegetable('veggie')
p = Potato()
v.message()
p.message()
Review Questions
Multiple Choice
1. In an inheritance relationship, the __________ is the general class.
a. subclass
b. superclass
c. slave class
d. child class
Review Questions 605
True or False
1. Polymorphism allows you to write methods in a subclass that have the same name as
methods in the superclass.
2. It is not possible to call a superclass’s _ _init_ _ method from a subclass’s
_ _init_ _ method.
3. A subclass can have a method with the same name as a method in the superclass.
4. Only the _ _init_ _ method can be overridden.
5. You cannot use the isinstance function to determine whether an object is an
instance of a subclass of a class.
Short Answer
1. What does a subclass inherit from its superclass?
2. Look at the following class definition. What is the name of the superclass? What is
the name of the subclass?
class Tiger(Felis):
3. What is an overridden method?
Algorithm Workbench
1. Write the first line of the definition for a Poodle class. The class should extend the
Dog class.
606 Chapter 11 Inheritance
Given these class definitions, what will the following statements display?
p = Plant('sapling')
t = Tree()
p.message()
t.message()
3. Look at the following class definition:
class Beverage:
def _ _init_ _(self, bev_name):
self._ _bev_name = bev_name
Write the code for a class named Cola that is a subclass of the Beverage class. The
Cola class’s _ _init_ _ method should call the Beverage class’s _ _init_ _ method,
passing ‘cola’ as an argument.
Programming Exercises
1. Employee and ProductionWorker Classes
Write an Employee class that keeps data attributes for the following pieces of information:
• Employee name
• Employee number
Next, write a class named ProductionWorker that is a subclass of the Employee class.
The ProductionWorker class should keep data attributes for the following information:
• Shift number (an integer, such as 1, 2, or 3)
• Hourly pay rate
The workday is divided into two shifts: day and night. The shift attribute will hold an
integer value representing the shift that the employee works. The day shift is shift 1 and the
night shift is shift 2. Write the appropriate accessor and mutator methods for each class.
Once you have written the classes, write a program that creates an object of the
ProductionWorker class and prompts the user to enter data for each of the object’s data
attributes. Store the data in the object, then use the object’s accessor methods to retrieve it
and display it on the screen.
Programming Exercises 607
2. ShiftSupervisor Class
In a particular factory, a shift supervisor is a salaried employee who supervises a shift. In
addition to a salary, the shift supervisor earns a yearly bonus when his or her shift meets
production goals. Write a ShiftSupervisor class that is a subclass of the Employee class
you created in Programming Exercise 1. The ShiftSupervisor class should keep a data
attribute for the annual salary, and a data attribute for the annual production bonus that
a shift supervisor has earned. Demonstrate the class by writing a program that uses a
ShiftSupervisor object.