Py Tutorial 29 56

Download as pdf or txt
Download as pdf or txt
You are on page 1of 28

1.11.

DEFINING FUNCTIONS OF YOUR OWN 29

def f(x):
return x*x

print(f(3))
print(f(3) + f(4))
The new Python syntax is the return statement, with the word return followed by an expression. Functions
that return values can be used in expressions, just like in math class. When an expression with a function
call is evaluated, the function call is effectively replaced temporarily by its returned value. Inside the Python
function, the value to be returned is given by the expression in the return statement. After the function f
finishes executing from inside
print(f(3))
it is as if the statement temporarily became
print(9)
and similarly when executing
print(f(3) + f(4))
the interpreter first evaluates f(3) and effectively replaces the call by the returned result, 9, as if the statement
temporarily became
print(9 + f(4))
and then the interpreter evaluates f(4) and effectively replaces the call by the returned result, 16, as if the
statement temporarily became
print(9 + 16)
resulting finally in 25 being calculated and printed.
Python functions can return any type of data, not just numbers, and there can be any number of
statements executed before the return statement. Read, follow, and run the example program return2.py:
def lastFirst(firstName, lastName): #1
separator = ’, ’ #2
result = lastName + separator + firstName #3
return result #4

print(lastFirst(’Benjamin’, ’Franklin’)) #5
print(lastFirst(’Andrew’, ’Harrington’)) #6
The code above has a new feature, variables separator and result are given a value in the function, but
separator and result are not among the formal parameters. The assignments work as you would expect
here. More on this shortly, in Section 1.11.8 on local scope.
Details of the execution:
(1) Lines 1-4: Remember the definition
(2) Line 5: call the function, remembering where to return
(3) Line 1: pass the parameters: firstName = ’Benjamin’; lastName = ’Franklin’
(4) Line 2: Assign the variable separator the value ’, ’
(5) Line 3: Assign the variable result the value of
lastName + separator + firstName which is
’Franklin’ + ’, ’ + ’Benjamin’, which evaluates to
’Franklin, Benjamin’
(6) Line 4: Return ’Franklin, Benjamin’
(7) Line 5 Use the value returned from the function call so the line effectively becomes
print(’Franklin, Benjamin’)
so print it.
(8) Line 6: call the function with the new actual parameters, remembering where to return
(9) Line 1: pass the parameters: firstName = ’Andrew’; lastName = ’Harrington’
(10) Lines 2-4: ... calculate and return ’Harrington, Andrew’
(11) Line 6: Use the value returned by the function and print ’Harrington, Andrew’
1.11. DEFINING FUNCTIONS OF YOUR OWN 30

Compare return2.py and addition5.py, from the previous section. Both use functions. Both print, but
where the printing is done differs. The function sumProblem prints directly inside the function and returns
nothing explicitly. On the other hand lastFirst does not print anything but returns a string. The caller
gets to decide what to do with the string, and above it is printed in the main program.
Open addition5.py again, and introduce a common mistake. Change the last line of the function main
inserting print, so it says
print(sumProblem(a, b))
Then try running the program. The desired printing is actually done inside the function sumProblem. You
introduced a statement to print what sumProblem returns. Although sumProblem returns nothing explicitly,
Python does make every function return something. If there is nothing explicitly returned, the special value
None is returned. You should see that in the Shell output. This is a fairly common error. If you see a ’None’
is your output where you do not expect it, it is likely that you have printed the return value of a function
that did not return anything explicitly!
Exercise 1.11.6.1. Create quotientReturn.py by modifying quotientProb.py from Exercise 1.11.5.1 so
that the program accomplishes the same thing, but everywhere change the quotientProblem function into
one called quotientString that merely returns the string rather than printing the string directly. Have the
main function print the result of each call to the quotientString function.
1.11.7. Two Roles: Writer and Consumer of Functions. The remainder of Section1.11 covers
finer points about functions that you might skip on a first reading.
We are only doing tiny examples so far to get the basic idea of functions. In much larger programs,
functions are useful to manage complexity, splitting things up into logically related, modest sized pieces.
Programmers are both writers of functions and consumers of the other functions called inside their functions.
It is useful to keep those two roles separate:
The user of an already written function needs to know:
(1) the name of the function
(2) the order and meaning of parameters
(3) what is returned or produced by the function
How this is accomplished is not relevant at this point. For instance, you use the work of the Python
development team, calling functions that are built into the language. You need know the three facts about
the functions you call. You do not need to know exactly how the function accomplishes its purpose.
On the other hand when you write a function you need to figure out exactly how to accomplish your
goal, name relevant variables, and write your code, which brings us to the next section.

1.11.8. Local Scope. For the logic of writing functions, it is important that the writer of a function
knows the names of variables inside the function. On the other hand, if you are only using a function, maybe
written by someone unknown to you, you should not care what names are given to values used internally in
the implementation of the function you are calling. Python enforces this idea with local scope rules: Variable
names initialized and used inside one function are invisible to other functions. Such variables are called
local variables. For example, an elaboration of the earlier program return2.py might have its lastFirst
function with its local variable separator, but it might also have another function that defines a separator
variable, maybe with a different value like ’\n’. They do not conflict. They are independent. This avoids
lots of errors!
For example, the following code in the example program badScope.py causes an execution error. Read
it and run it, and see:
def main():
x = 3
f()

def f():
print(x) #f does not know about the x defined in main

main()
1.12. DICTIONARIES 31

We will fix this error below. The execution error message mentions “global name”. Names defined outside
any function definition, at the “top-level” of your program are called global. They are a special case. They
are discussed more in the next section.
If you do want local data from one function to go to another, define the called function so it includes
parameters! Read and compare and try the program goodScope.py:
def main():
x = 3
f(x)

def f(x):
print(x)

main()
With parameter passing, the parameter name x in the function f does not need to match the name of the
actual parameter in main. The definition of f could just as well have been:
def f(whatever):
print(whatever)
1.11.9. Global Constants. If you define global variables (outside of any function definition), they are
visible inside all of your functions. It is good programming practice to avoid defining global variables and
instead to put your variables inside functions and explicitly pass them as parameters where needed. One
common exception is constants: A constant is a name that you give a fixed data value to, by assigning a
value to the name only in a single assignment statement. You can then use the name of the fixed data value
in expressions later. A simple example program is constant.py:

PI = 3.14159265358979 # global constant -- only place the value of PI is set

def circleArea(radius):
return PI*radius*radius # use value of global constant PI

def circleCircumference(radius):
return 2*PI*radius # use value of global constant PI

print(’circle area with radius 5:’, circleArea(5))


print(’circumference with radius 5:’, circleCircumference(5))
This example uses numbers with decimal points, discussed more in Section 1.14.1. By convnetion, names
for constants are all capital letters.
Issues with global variables do not come up if they are only used as constants.
Function names defined at the top-level also have global scope. This is what allows you to use one
function you defined inside another function you define.

1.12. Dictionaries
1.12.1. Definition and Use of Dictionaries. In common usage, a dictionary is a collection of words
matched with their definitions. Given a word, you can look up its definition. Python has a built in dictionary
type called dict which you can use to create dictionaries with arbitrary definitions for character strings. It
can be used for the common usage, as in a simple English-Spanish dictionary.
Look at the example program spanish1.py and run it.
"""A tiny English to Spanish dictionary is created,
using the Python dictionary type dict.
Then the dictionary is used, briefly.
"""

spanish = dict()
1.12. DICTIONARIES 32

spanish[’hello’] = ’hola’
spanish[’yes’] = ’si’
spanish[’one’] = ’uno’
spanish[’two’] = ’dos’
spanish[’three’] = ’tres’
spanish[’red’] = ’rojo’
spanish[’black’] = ’negro’
spanish[’green’] = ’verde’
spanish[’blue’] = ’azul’

print(spanish[’two’])
print(spanish[’red’])

First an empty dictionary is created using dict(), and it is assigned the descriptive name spanish.
To refer to the definition for a word, you use the dictionary name, follow it by the word inside square
brackets. This notation can either be used on the left-hand side of an assignment to make (or remake) a
definition, or it can be used in an expression (as in the print functions), where its definition is one stored
earlier into the dictionary. For example,
spanish[’hello’] = ’hola’
makes an entry in our spanish dictionary for ’hello’ , where the definition matched to it is ’hola’.
print(spanish[’red’])
retrieves the definition for ’red’, which is ’rojo’.
Since the Spanish dictionary is defined at the top-level, the variable name spanish is still defined after
the program runs: after running the program, use spanish in the Shell to check out the translations of some
more words, other than ’two’ and ’red’.
Creating the dictionary is quite a different activity from the use at the end of the code, so with functions
to encapsulate the tasks, we could write the example program spanish2.py instead, with the same result:

"""A tiny English to Spanish dictionary is created,


using the Python dictionary type dict.
Then the dictionary is used, briefly.
"""

def createDictionary():
’’’Returns a tiny Spanish dictionary’’’
spanish = dict() # creates an empty dictionary
spanish[’hello’] = ’hola’
spanish[’yes’] = ’si’
spanish[’one’] = ’uno’
spanish[’two’] = ’dos’
spanish[’three’] = ’tres’
spanish[’red’] = ’rojo’
spanish[’black’] = ’negro’
spanish[’green’] = ’verde’
spanish[’blue’] = ’azul’
return spanish

def main():
dictionary = createDictionary()
print(dictionary[’two’])
print(dictionary[’red’])

main()

This code illustrates several things about functions.


1.12. DICTIONARIES 33

• First, like whole files, functions can have a documentation string immediately after the definition
heading. It is a good idea to document the return value!
• The dictionary that is created is returned, but the local variable name in the function, spanish, is
lost when the function terminates.
• In main, to remember the dictionary returned, it needs a name. The name does not have to match
the name used in createDictionary. The name dictionary is descriptive.
We could also use the dictionary more extensively. The example program spanish2a.py is the same as above
except it has the following main method
def main():
dictionary = createDictionary()
print(’Count in Spanish: ’ + dictionary[’one’] + ’, ’ +
dictionary[’two’] + ’, ’ + dictionary[’three’] + ’,...’)
print(’Spanish colors: ’ + dictionary[’red’] + ’, ’ +
dictionary[’blue’] + ’, ’ + dictionary[’green’] + ’,...’)
Try it, and check that it makes sense.
Python dictionaries are actually more general than the common use of dictionaries. They do not have to
associate words and their string definitions. They can associate many types of objects with some arbitrary
object. The more general Python terminology for word and definition are key and value. Given a key, you
can look up the corresponding value. The only restriction on the key is that it be an immutable type. This
means that a value of the key’s type cannot be changed internally after it is initially created. Strings and
numbers are immutable. A dictionary is mutable: its value can be changed internally. (You can add new
definitions to it!) We will see more mutable and immutable types later and explore more of the internal
workings of data types.
Exercise 1.12.1.1. * Write a tiny Python program numDict.py that makes a dictionary whose keys
are the words ’one’, ’two’, ’three’, and ’four’, and whose corresponding values are the numerical equivalents,
1, 2, 3, and 4 (ints, not strings). Include code to test the resulting dictionary by referencing several of the
definitions and printing the results.
1.12.2. Dictionaries and String Formatting. At the end of the main function in spanish2a.py
from the last section, two strings are constructed and printed. The expressions for the two strings include a
sequence of literal strings concatenated with interspersed values from a dictionary. There is a much neater,
more readable way to generate these strings. We will develop this in several steps. The first string could be
constructed and printed as follows:
numberFormat = "Count in Spanish: {one}, {two}, {three}, ..."
withSubstitutions = numberFormat.format(one=’uno’, two=’dos’, three=’tres’)
print(withSubstitutions)
There are several new ideas here!.
Note the form of the string assigned the name numberFormat: It has the English words for numbers in
braces where we want the Spanish definitions substituted.
The second line uses method calling syntax. You will see this in more detail at the beginning of the next
chapter. Strings and other objects have a special syntax for functions tightly associated with the particular
type of object. Such functions are called methods. In particular str objects have a method called format.
The syntax for methods
object.methodname(paramters)
has the object followed by a period followed by the method name, and further parameters in parentheses.
In the example above, the object is the string called numberFormat. The method is named format. The
parameters in this case are all keyword parameters. You have already seen keyword parameters sep and end
used in print function calls. In this particular application, the keywords are chosen to include all the words
that appear enclosed in braces in the numberFormat string.
When the string numberFormat has the format method applied to it with the given keyword parameters,
a new string is created with substitutions into the places enclosed in braces. The substitutions are just the
values given by the keyword parameters. Hence the printed result is
Count in Spanish: uno, dos, tres, ...
1.12. DICTIONARIES 34

Now we go one step further: The keyword parameters associate the keyword names with the values after the
equal signs. The dictionary from spanish2a.py includes exactly the same associations. There is a special
notation allowing such a dictionary to supply keyword parameters. Assuming dictionary is the Spanish
dictionary from spanish2a.py, the method call
numberFormat.format(one=’uno’, two=’dos’, three=’tres’)
returns the same string as
numberFormat.format(**dictionary)
The special syntax ** before the dictionary indicates that the dictionary is not to be treated as a single
regular parameter. Instead keyword arguments for all the entries in the dictionary effectively appear in its
place.
Below is a substitute for the main method in spanish2a.py. The whole revised program is in example
program spanish3.py.
def main():
dictionary = createDictionary()
numberFormat = "Count in Spanish: {one}, {two}, {three}, ..."
withSubstitutions = numberFormat.format(**dictionary)
print(withSubstitutions)
print("Spanish colors: {red}, {blue}, {green}, ...".format(**dictionary))

The string with the numbers is constructed in steps as discussed above. The printing of the string with the
Spanish colors is coded more concisely. There are not named variables for the format string or the resulting
formatted string. You are free to use either coding approach.
In general, use this syntax for the string format method with a dictionary, returning a new formatted
string:
formatString.format(**aDictionary)
where the format string contains dictionary keys in braces where you want the dictionary values substituted.
The dictionary key names must follow the rules for legal identifiers.
At this point we have discussed in some detail everything that went into the first sample program,
madlib.py, of Section 1.2.3! This is certainly the most substantial program so far.
Look at madlib.py again, see how we have used most of the ideas so far. If you want more description,
you might look at section 1.2.3 again (or for the first time): it should make much more sense now.
Exercise 1.12.2.1. To confirm your better understanding of madlib.py, load it in the editor, rename
it as myMadlib.py, and modify it to have a less lame story, with more and different entries in the dictionary.
Make sure addPick is called for each key in your format string. Test your version.
We will use madlib.py as a basis for more substantial modifications in structure in Section 2.3.3.
1.12.3. Dictionaries and Python Variables. Dictionaries are central to the implementation of
Python. Each variable identifier is associated with a particular value. These relationships are stored in
dictionaries in Python, and these dictionaries are accessible to the user: You can use the function call
locals() to return a dictionary containing all the current local variables names as keys and all their values
as the corresponding dictionary values. This dictionary can be used with the string format method, so you
can embed local variable names in a format string and use then very easily!
For example, run the example program arithDict.py:
’’’Fancier format string example, with locals().’’’

x = 20
y = 30
sum = x+y
prod = x*y
formatStr = ’{x} + {y} = {sum}; {x} * {y} = {prod}.’
equations = formatStr.format(**locals())
print(equations)
1.13. LOOPS AND SEQUENCES 35

Note the variable names inside braces in formatStr, and the dictionary reference used as the format pa-
rameter is **locals().
A string like formatStr is probably the most readable way to code the creation of a string from a
collection of literal strings and program values. The ending part of the syntax, .format(**locals()), may
appear a bit strange, but it is very useful! We will use this notation extensively to clearly indicate how
values are embedded into strings.
The example program hello_you4.py does the same thing as the earlier hello_you versions, but with
a dictionary reference:
person = input(’Enter your name: ’)
greeting = ’Hello {person}!’.format(**locals())
print(greeting)

1.13. Loops and Sequences


Modern computers can do millions or even billions of instructions a second. With the techniques discussed
so far, it would be hard to get a program that would run by itself for more than a fraction of a second.6
Practically, we cannot write millions of instructions to keep the computer busy. To keep a computer doing
useful work we need repetition, looping back over the same block of code again and again. There are two
Python statement types to do that: the simpler for loops, which we take up shortly, and while loops,
which we take up later, in Section 3.3. Two preliminaries: First, the value of already defined variables can be
updated. This will be particularly important in loops. We start by following how variables can be updated in
an even simpler situation. Second, for loops involve sequence types, so we will first look at a basic sequence
type: list. This is a long section. Go carefully.
1.13.1. Updating Variables. The programs so far have defined and used variables, but other than
in early shell examples we have not changed the value of existing variables. For now consider a particularly
simple example, just chosen as an illustration, in the example file updateVar.py:
x = 3 #1
y = x + 2 #2
y = 2*y #3
x = y - x #4
print(x, y) #5
Can you predict the result? Run the program and check. Particularly if you did not guess right, it is
important to understand what happens, one step at a time. That means keeping track of what changes to
variables are made by each statement. In the table below, statements are referred to by the numbers labeling
the lines in the code above. We can track the state of each variable after each line in executed. A dash is
shown where a variable is not defined. For instance after line 1 is executed, a value is given to x, but y is
still undefined. Then y gets a value in line 2. The comment on the right summarizes what is happening.
Since x has the value 3 when line 2 starts, x+2 is the same as 3+2. In line three we use the fact that the
right side of an assignment statement uses the values of variables when the line starts executing (what is
left after the previous line of the table executed), but the assignment to the variable y on the left causes a
change to y, and hence the updated value of y, 10, is shown in the table. Line 4 then changes x, using the
latest value of y (10, not the initial value 5!). The result from line 5 confirms the values of x and y.
Line x y comment
1 3 -
2 3 5 5=3+2, using the value of x from the previous line
3 3 10 10=2*5 on the right, use the value of y from the previous line
4 7 19 7=10-3 on the right, use the value of x and y from the previous line
5 7 10 print: 7 10
The order of execution will always be the order of the lines in the table. In this simple sequential code,
that also follows the textual order of the program. Following each line of execution of a program in order,
carefully, keeping track of the current values of variables, will be called playing computer. A table like the
one above is an organized way to keep track.
6It is possible with function recursion, but we will avoid that topic in this introduction.
1.13. LOOPS AND SEQUENCES 36

1.13.2. The list Type. Lists are ordered sequences of arbitrary data. Lists are the first kind of data
discussed so far that are mutable: the length of the sequence can be changed and elements substituted. We
will delay the discussion of changes to lists until a further introduction to objects. Lists can be written
explicitly. Read the following examples
[’red’, ’green’, ’blue’]
[1, 3, 5, 7, 9, 11]
[’silly’, 57, ’mixed’, -23, ’example’]
[] # the empty list
The basic format is square-bracket-enclosed, comma-separated lists of arbitrary data.

1.13.3. The range Function, Part 1. There is a built-in function range, that can be used to auto-
matically generate regular arithmetic sequences. Try the following in the Shell:
list(range(4))
list(range(10))
The general pattern for use is
range(sizeOfSequence)
This syntax will generate the items, one at a time, as needed. If you want to see all the results at once as a
list, you can convert to a list as in the examples above. The resulting sequence starts at 0 and ends before
the parameter. We will see there are good reasons to start from 0 in Python. One important property of
sequences generated by range(n) is that the total number of elements is n. The sequence omits the number
n itself, but includes 0 instead.
With more parameters, the range function can be used to generate a much wider variety of sequences.
The elaborations are discussed in Section 2.4.12 and Section 3.3.2.

1.13.4. Basic for Loops. Try the following in the Shell. You get a sequence of continuation lines
before the Shell responds. Be sure to indent the second and third lines. (This is only needed inthe Shell, not
in an edit window, where the indentation is automatic). Be sure to enter another empty line (just Enter)
at the end to get the Shell to respond.
for count in [1, 2, 3]:
print(count)
print(’Yes’ * count)
This is a for loop. It has the heading starting with for, followed by a variable name (count in this case), the
word in, some sequence, and a final colon. As with function definitions and other heading lines ending with
a colon, the colon at the end of the line indicates that a consistently indented block of statements follows to
complete the for loop.
for item in sequence:
indented statements to repeat
The block of lines is repeated once for each element of the sequence, so in this example the two lines in the
indented block are repeated three times. Furthermore the variable in the heading (count here) may be used
in the block, and each time through it takes on the next value in the sequence, so the first time through the
loop count is 1, then 2, and finally 3. Look again at the output and see that it matches this sequence.
There is a reason the interpreter waited to respond until after you entered an empty line: The interpreter
did not know how long the loop block was going to be! The empty line is a signal to the interpreter that
you are done with the loop block.
Look at the following example program for123.py, and run it.
for count in [1, 2, 3]: #1
print(count) #2
print(’Yes’*count) #3
print(’Done counting.’) #4
for color in [’red’, ’blue’, ’green’]: #5
print(color) #6
1.13. LOOPS AND SEQUENCES 37

In a file, where the interpreter does not need to respond immediately, the blank line is not necessary. Instead,
as with a function definition or any other format with an indented block, you indicate being past the indented
block by dedenting to line up with the for-loop heading. Hence in the code above, “Done Counting.” is
printed once after the first loop completes all its repetitions. Execution ends with another simple loop.
As with the indented block in a function, it is important to get the indentation right. Alter the code
above, so line 4 is indented:
for count in [1, 2, 3]: #1
print(count) #2
print(’Yes’*count) #3
print(’Done counting.’) #4
for color in [’red’, ’blue’, ’green’]: #5
print(color) #6
Predict the change, and run the code again to test.
Loops are one of the most important features in programming. While the syntax is pretty simple, using
them creatively to solve problems (rather than just look at a demonstration) is among the biggest challenges
for many learners at an introductory level. One way to simplify the learning curve is to classify common
situations and patterns. One of the simplest patterns is illustrated above, simple for-each loops.
for item in sequence
do some thing with item
(It would be even more like English if for were replace by for each, but the shorter version is the one used
by Python.)
In the for-loop examples above, something is printed that is related to each item in the list. Printing is
certainly one form of “do something”, but the possibilities for “do something” are completely general!
We can use a for-each loop to revise our first example. Recall the code from madlib.py:
addPick(’animal’, userPicks)
addPick(’food’, userPicks)
addPick(’city’, userPicks)
Each line is doing exactly the same thing, except varying the string used as the cue, while repeating the rest
of the line. This is the for-each pattern, but we need to list the sequence that the cues come from. Read the
alternative:
for cue in [’animal’, ’food’, ’city’]: # heading
addPick(cue, userPicks) # body
If you wish to see or run the whole program with this small modification, see the example madlibloop.py.
It is important to understand the sequence of operations, how execution goes back and forth between
the heading and the body. Here are the details:
(1) heading first time: variable cue is set to the first element of the sequence, ’animal’
(2) body first time: since cue is now ’animal’, effectively execute addPick(’animal’, userPicks)
(Skip the details of the function call in this outline.)
(3) heading second time: variable cue is set to the next element of the sequence, ’food’
(4) body second time: since cue is now ’food’, effectively execute addPick(’food’, userPicks)
(5) heading third time: variable cue is set to the next (last) element of the sequence, ’city’
(6) body third time: since cue is now ’city’, effectively execute addPick(’city’, userPicks)
(7) heading done: Since there are no more elements in the sequence, the entire for loop is done and
execution would continue with the statement after it.
This looping construction would be even handier if you were to modify the original mad lib example, and
had a story with many more cues. Also this revision will allow for further improvements in Section 2.3.3,
after we introduce more about string manipulation.
1.13.5. Simple Repeat Loops. The examples above all used the value of the variable in the for-loop
heading. An even simpler for-loop usage is when you just want to repeat the exact same thing a specific
number of times. In that case only the length of the sequence, not the individual elements are important.
We have already seen that the range function provides an ease way to produce a sequence with a specified
number of elements. Read and run the example program repeat1.py:
1.13. LOOPS AND SEQUENCES 38

for i in range(10):
print(’Hello’)
In this situation, the variable i is not used inside the body of the for-loop.
The user could choose the number of times to repeat. Read and run the example program repeat2.py:
n = int(input(’Enter the number of times to repeat: ’))
for i in range(n):
print(’This is repetitious!’)
1.13.6. Successive Modification Loops. Suppose I have a list of items called items, and I want to
print out each item and number them successively. For instance if items is [’red’, ’orange’, ’yellow’, ’green’],
I would like to see the output:
1 red
2 orange
3 yellow
4 green
Read about the following thought process for developing this:
If I allow myself to omit the numbers, it is easy: For any item in the list, I can process it with
print(item)
and I just go through the list and do it for each one. (Copy and run if you like.)
items = [’red’, ’orange’, ’yellow’, ’green’]
for item in items:
print(item)
Clearly the more elaborate version with numbers has a pattern with some consistency, each line is at least
in the form:
number item
but the number changes each time, and the numbers do not come straight from the list of items.
A variable can change, so it makes sense to have a variable number, so we have the potential to make it
change correctly. We could easily get it right the first time, and then repeat the same number. Read and
run the example program numberEntries1.py:
items = [’red’, ’orange’, ’yellow’, ’green’]
number = 1
for item in items:
print(number, item)
Of course this is still not completely correct, since the idea was to count. After the first time number is
printed, it needs to be changed to 2, to be right the next time through the loop, as in the following code:
Read and run the example program numberEntries2.py:
items = [’red’, ’orange’, ’yellow’, ’green’]
number = 1
for item in items:
print(number, item)
number = 2
This is closer, but still not completely correct, since we never get to 3! We need a way to change the value of
number that will work each time through the loop. The pattern of counting is simple, so simple in fact that
you probably do not think consciously about how you go from one number to the next: You can describe
the pattern by saying each successive number is one more than the previous number. We need to be able to
change number so it is one more than it was before. That is the additional idea we need! Change the last
line of the loop body to get the example program numberEntries3.py. See the addition and run it:
items = [’red’, ’orange’, ’yellow’, ’green’] #1
number = 1 #2
for item in items: #3
print(number, item) #4
number = number + 1 #5
1.13. LOOPS AND SEQUENCES 39

It is important to understand the step-by-step changes during execution. Below is another table showing
the results of playing computer. The line numbers are much more important here to keep track of the flow
of control, because of the jumping around at the end of the loop.
Line items item number comment
1 [’red’, ’orange’, ’yellow’, ’green’] - -
2 [’red’, ’orange’, ’yellow’, ’green’] - 1
3 [’red’, ’orange’, ’yellow’, ’green’] ’red’ 1 start with item as first in sequence
4 [’red’, ’orange’, ’yellow’, ’green’] ’red’ 1 print: 1 red
5 [’red’, ’orange’, ’yellow’, ’green’] ’red’ 2 2 = 1+1
3 [’red’, ’orange’, ’yellow’, ’green’] ’orange’ 2 on to the next element in sequence
4 [’red’, ’orange’, ’yellow’, ’green’] ’orange’ 2 print 2 orange
5 [’red’, ’orange’, ’yellow’, ’green’] ’orange’ 3 3=2+1
3 [’red’, ’orange’, ’yellow’, ’green’] ’yellow’ 3 on to the next element in sequence
4 [’red’, ’orange’, ’yellow’, ’green’] ’yellow’ 3 print 3 yellow
5 [’red’, ’orange’, ’yellow’, ’green’] ’yellow’ 4 4=3+1
3 [’red’, ’orange’, ’yellow’, ’green’] ’green’ 4 on to the last element in sequence
4 [’red’, ’orange’, ’yellow’, ’green’] ’green’ 4 print 4 green
5 [’red’, ’orange’, ’yellow’, ’green’] ’green’ 5 5=4+1
3 [’red’, ’orange’, ’yellow’, ’green’] ’green’ 5 sequence done, end loop and code
The final value of number is never used, but that is OK. What we want is printed.
This short example illustrates a lot of ideas:
• Loops may contain several variables.
• One way a variable can change is by being the variable in a for-loop heading, that automatically
goes through the values in the for-loop list.
• Another way to have variables change in a loop is to have an explicit statement that changes the
variable inside the loop, causing successive modifications.
There is a general pattern to loops with successive modification of a variable like number above:
(1) The variables to be modified need initial values before the loop (line 1 in the example above).
(2) The loop heading causes the repetition. In a for-loop, the number of repetitions is the same as the
size of the list.
(3) The body of the loop generally “does something” (like print above in line 4) that you want done
repeatedly.
(4) There is code inside the body of the loop to set up for the next time through the loop, where the
variable which needs to change gets transformed to its next value (line 5 in the example above).
This information can be put in a code outline:
Initialize variables to be modified
Loop heading controlling the repetition
Do the desired action with the current variables
Modify variables to be ready for the action the next time
If you compare this pattern to the for-each and simple repeat loops in Section 1.13.4, you see that the
examples there were simpler. There was no explicit variable modification needed to prepare for the next
time though the loop. We will refer to the latest, more general pattern as a successive modification loop.
Functions are handy for encapsulating an idea for use and reuse in a program, and also for testing. We
can write a function to number a list, and easily test it with different data. Read and run the example
program numberEntries4.py:
def numberList(items):
’’’Print each item in a list items, numbered in order.’’’
number = 1
for item in items:
print(number, item)
number = number + 1
1.13. LOOPS AND SEQUENCES 40

def main():
numberList([’red’, ’orange’, ’yellow’, ’green’])
print()
numberList([’apples’, ’pears’, ’bananas’])

main()
Make sure you can follow the whole sequence, step by step! This program has the most complicated flow of
control so far, changing both for function calls and loops.
(1) Execution start with the very last line, since the previous lines are definitions
(2) Then main starts executing.
(3) The first call to numberList effectively sets the formal parameter
items = [’red’, ’orange’, ’yellow’, ’green’]
and the function executes just like the flow followed in numberEntries3.py. This time, however,
execution returns to main.
(4) An empty line is printed in the second line of main.
(5) The second call to numberList has a different actual parameter [’apples’, ’pears’, ’bananas’],
so this effectively sets the formal parameter this time
items = [’apples’, ’pears’, ’bananas’]
and the function executes in a similar pattern as in numberEntries3.py, but with different data
and one less time through the loop.
(6) Execution returns to main, but there is nothing more to do.
1.13.7. Accumulation Loops. Suppose you want to add up all the numbers in a list, nums. Let us
plan this as a function from the beginning, so read the code below. We can start with:
def sumList(nums):
’’’Return the sum of the numbers in nums.’’’
If you do not see what to do right away, a useful thing to do is write down a concrete case, and think how
you would solve it, in complete detail. If nums is [2, 6, 3, 8], you would likely calculate

2+6 is 8
8 + 3 is 11
11 + 8 is 19
19 is the answer to be returned.

Since the list may be arbitrarily long, you need a loop. Hence you must find a pattern so that you can keep
reusing the same statements in the loop. Obviously you are using each number in the sequence in order.
You also generate a sum in each step, which you reuse in the next step. The pattern is different, however,
in the first line, 2+6 is 8: there is no previous sum, and you use two elements from the list. The 2 is not
added to a previous sum.
Although it is not the shortest way to do the calculation by hand, 2 is a sum of 0 + 2: We can make the
pattern consistent and calculate:

start with a sum of 0


0 + 2 is 2
2 + 6 is 8
8 + 3 is 11
11 + 8 is 19
19 is the answer.

Then the second part of each sum is a number from the list, nums. If we call the number from the list num,
the main calculation line in the loop could be
nextSum = sum + num
1.13. LOOPS AND SEQUENCES 41

The trick is to use the same line of code the next time through the loop. That means what was nextSum in
one pass becomes the sum in the next pass. One way to handle that is:

sum = 0
for num in nums:
nextSum = sum + num
sum = nextSum

Do you see the pattern? Again it is

initialization
loop heading
main work to be repeated
preparation for the next time through the loop

Sometimes the two general loop steps can be combined. This is such a case. Since nextSum is only used
once, we can just substitute its value (sum) where it is used and simplify to:

sum = 0
for num in nums:
sum = sum + num

so the whole function, with the return statement is:

def sumList(nums): #1
’’’Return the sum of the numbers in nums.’’’
sum = 0 #2
for num in nums: #3
sum = sum + num #4
return sum #5

With the following (not indented) line below used to test the function, you have the example program
sumNums.py. Run it.

print(sumList([5, 2, 4, 7]))

The pattern used here is certainly successive modification (of the sum variable). It is useful to give a more
specialized name for this version of the pattern here. It follows an accumulation pattern:

initialize the accumulation to include none of the sequence (sum = 0 here)


for item in sequence :
new value of accumulation = result of combining item with last value of accumulation

This pattern will work in many other situations besides adding numbers.

Exercise 1.13.7.1. * Suppose the function sumList, is called with the parameter [5, 2, 4, 7]. Play
computer on this call. Make sure there is a row in the table for each line executed in the program, each
time it is executed. In each row enter which program line is being executed and show all changes caused to
variables by the execution of the line. A table is started for you below. The final line of your table should
be for line 5, with the comment, “return 18”. If you do something like this longhand, and the same long
value repeats a number of times, it is more convenient to put a ditto (“) for each repeated variable value or
even leave it blank. If you want to do it on a computer you can start from the first table in example file
playComputerSumStub.rtf. First save the file as playComputerSum.rtf.
1.13. LOOPS AND SEQUENCES 42

Line nums sum num comment


1 [5, 2, 4, 7] - -
2

Exercise 1.13.7.2. * Write a program testSumList.py which includes a main function to test the
sumList function several times. Include a test for the extreme case, with an empty list.

Exercise 1.13.7.3. ** Complete the following function. This starting code is in joinAllStub.py. Save
it to the new name joinAll.py. Note the way an example is given in the documentation string. It simulates
the use of the function in the Shell. This is a common convention:
def joinStrings(stringList):
’’’Join all the strings in stringList into one string,
and return the result. For example:

>>> print(joinStrings([’very’, ’hot’, ’day’]))


’veryhotday’
’’’
7 8
Hint1: Hint2:

1.13.8. More Playing Computer. Testing code by running it is fine, but looking at the results does
not mean you really understand what is going on, particularly if there is an error! People who do not
understand what is happening are likely to make random changes to their code in an attempt to fix errors.
This is a very bad, increasingly self-defeating practice, since you are likely to never learn where the real
problem lies, and the same problem is likely to come back to bite you.
It is important to be able to predict accurately what code will do. We have illustrated playing computer
on a variety of small chunks of code.
Playing computer can help you find bugs (errors in your code). Some errors are syntax errors caught by
the interpreter in translation. Some errors are only caught by the interpreter during execution, like failing
to have a value for a variable you use. Other errors are not caught by the interpreter at all – you just get
the wrong answer. These are called logical errors. Earlier logical errors can also trigger an execution error
later. This is when playing computer is particularly useful.
A common error in trying to write the numberList function would be to have:
def numberList(items): # WRONG code for illustration!!!! #1
’’’Print each item in a list items, numbered in order.’’’ #2
for item in items: #3
number = 1 #4
print(number, item) #5
number = number + 1 #6
You can run this code in numberEntriesWRONG.py and see that it produces the wrong answer. If you play
computer on the call to numberList([’apples’, ’pears’, ’bananas’]), you can see the problem:

7This is a form of accumulation, but not quite the same as adding numbers.
8“Start with nothing accumulated” does not mean 0, here. Think what is appropriate.
1.13. LOOPS AND SEQUENCES 43

Line items item number comment


1 [’apples’, ’pears’, ’bananas’] - - pass actual parameter value to items
3 [’apples’, ’pears’, ’bananas’] ’apples’ - start with item as first in sequence
4 [’apples’, ’pears’, ’bananas’] ’apples’ 1
5 [’apples’, ’pears’, ’bananas’] ’apples’ 1 print: 1 apples
6 [’apples’, ’pears’, ’bananas’] ’apples’ 2 2 = 1+1
3 [’apples’, ’pears’, ’bananas’] ’pears’ 2 on to the next element in sequence
4 [’apples’, ’pears’, ’bananas’] ’apples’ 1
5 [’apples’, ’pears’, ’bananas’] ’pears’ 1 print: 1 pears OOPS!
If you go step by step you should see where the incorrect 1 came from: the initialization is repeated each
time in the loop at line 4, undoing the incrementing of number in line 6, messing up your count. Always be
careful that your one-time initialization for a loop goes before the loop, not in it!
Functions can also return values. Consider the Python for this mathematical sequence: define the
function m(x) = 5x, let y = 3; find m(y) + m(2y-1).
def m(x): #1
return 5*x #2

y = 3 #3
print(m(y) + m(2*y-1)) #4
A similar example was considered in Section 1.11.6, but now add the idea of playing computer and recording
the sequence in a table. Like when you simplify a mathematical expression, Python must complete the
innermost parts first. Tracking the changes means following the function calls carefully and using the values
returned. Again a dash ’-’ is used in the table to indicate an undefined variable. Not only are local variables
like formal parameters undefined before they are first used, they are also undefined after the termination of
the function,
Line x y comment
3 - 3 (definitions only before this line)
4 - 3 start on: print m(y) + m(2*y-1); find m(y), which is m(3)
1 3 3 pass 3 to function m, so x =3
2 3 3 return 5*3 = 15
4 - 3 substitute result: print 15 + m(2*y-1), find m(2*y-1), which is m(2*3-1) = m(5)
1 5 3 pass 5 to function m, so x=5
2 5 3 return 5*5 = 25
4 - 3 substitute result: print 15 + 25, so calculate and print 40
Thus far most of the code given has been motivated first, so you are likely to have an idea what to
expect. You may need to read code written by someone else (or even yourself a while back!) where you are
not sure what is intended. Also you might make a mistake and accidental write code that does something
unintended! If you really understand how Python works, one line at a time, you should be able to play
computer and follow at least short code sequences that have not been explained before. It is useful to read
another person’s code and try to follow it. The next exercises also provides code that has not been explained
first:or has a mistake.
Exercise 1.13.8.1. ** Play computer on the following code. Reality check: 31 is printed when line 6
finally executes. Table headings are shown below to get you started with a pencil. Alternately you can work
in a word processor starting from playComputerStub.rtf, which has tables set up for this and the following
exercise. Save the file with an alternate name playComputer.rtf.
x = 0 #1
y = 1 #2
for n in [5, 4, 6]: #3
x = x + y*n #4
y = y + 1 #5

print(x) #6
1.13. LOOPS AND SEQUENCES 44

Line x y n Comment

Exercise 1.13.8.2. ** The following code is supposed to compute the product of the numbers in a list.
For instance product([5, 4, 6]) should calculate and return 5*4*6=120 in steps, calculating 5, 5*4=20
and 20*6=120 . Play computer on a call to product([5, 4, 6]) until you see that it makes a mistake. This
code appears in the example file numProductWrong.py. Save it as numProduct.py and fix the error (and
save again!). Table headings and the first row are shown below to get you started with a pencil. Alternately
you can work in a word processor continuing to add to playComputer.rtf, started in the previous exercise.
def product(nums): #1
for n in nums: #2
prod = 1 #3
prod = prod*n #4
return prod #5

Line nums n prod Comment


1 [5, 4, 6] - -

Exercise 1.13.8.3. ** Play computer on the following code. Table headings are shown for you. Reality
check: 70 is printed. See the previous exercises if you enter your answer in a file.
def f(x): #1
return x+4 #2

print(f(3)*f(6)) #3

Line x Comment

1.13.9. The print function end keyword. By default the print function adds a newline to the end
of the string being printed. this can be overridden by including the keyword parameter end. The keyword
end can be set equal to any string. The most common replacements are the empty string or a single blank.
If you also use the keyword parameter sep, these keyword paramters may be in either order, but they msut
come at the end of the parmater list. Read the illustrations:
print(’all’, ’on’, ’same’, ’line’)
print(’different line’)
is equivalent to
print(’all’, ’on’ , end = ’ ’)
print(’same’, end = ’ ’)
print(’line’)
print(’different line’)
This does not work directly in the shell (where you are always forced to a new line at the end). It does work
in a program, but it is not very useful except in a loop! Suppose I want to print a line with all the elements
of a list, separated by spaces, but not on separate lines. I can use the end keyword set to a space in the
loop. Can you figure out in your head what this example file endSpace1.py does? Then try it:
def listOnOneLine(items):
for item in items:
print(item, end=’ ’)

listOnOneLine([’apple’, ’banana’, ’pear’])


print(’This may not be what you expected!’)
If you still want to go on to a new line at the end of the loop, you must include a print function that does
advance to the next line, once, after the loop. Try this variation, endSpace2.py
1.14. DECIMALS, FLOATS, AND FLOATING POINT ARITHMETIC 45

def listOnOneLine(items):
for item in items:
print(item, end=’ ’)
print()

listOnOneLine([’apple’, ’banana’, ’pear’])


print(’This is probably better!’)

1.14. Decimals, Floats, and Floating Point Arithmetic


Floating point numbers like 12.345 are a basic type, but there are some complications due to their
inexactness. This section may be deferred until you actually need numbers other than integers.
1.14.1. Floats, Division, Mixed Types. As you moved on in school after your first integer division,
and did fractions and decimals, you probably thought of 6/8 as a fraction and could convert to a decimal
.75. Python can do decimal calculations, too, approximately.
Try all set-off lines in this section in the Shell:
6/8
6/3
2.3/25.7
There is more going on here than meets the eye. As you should know, decimal representations of values can
be a pain. They may not be able to be expressed with a finite number of characters. Try
2/3
Also, as you may have had emphasized in science class, real number measurements are often not exact, and
so the results of calculations with them are not exact. In fact there are an infinite number of real number
just between 0 and 1, and a computer is finite. It cannot store all those numbers exactly! On the other hand,
Python does store integers exactly (well at least far past the number of atoms in the universe – eventually
even integers could get too big to store in a computer). The difference in the way integers and decimals are
stored and processed leads to decimals and integers being different types in Python. Try
type(3.5)
Note that 3.5 is of type ’float’, not ’decimal’. There are several reasons for that name having to do with the
actual way the type is stored internally. “Decimal” implies base ten, our normal way for writing numbers
with ten digits 0,1,2,3,4,5,6,7,8,9. Computers actually use base two, with only two symbols 0,1. (Did you
note what symbols were in the machine language in Section 1.1?) Also floats use an encoding something like
scientific notation from science class, with exponents that allow the decimal point to move or “float”, as in
the decimal case: 2345.6 = (2.3456)103
Try
type(-2)
type(-2.0)
Even a number that is actually an integer can be represented in the float type if a decimal point is included.
Always be sure to remember that floats may not be exact. The use of base two makes this true even in
cases where decimal numbers can be expressed exactly! More on that at the end of this section on formatting
floats.
It is sometimes important to know the numeric type of a Python value. Any combination of +, -, and *
with operands of type int produces an int. If there is an operation /, or if any operand is of type float, the
result is float. Try each in the Shell (and guess the resulting type):9
3.3 - 1.1
2.0 + 3
2.5*2
9Python 3.1 does what you would expect mathematically with an expression like

(1/2)*6.5
Caution: This is not the case in other common languages like Java and C++ (or with versions of Python before 3.0). They
treat the / operation with integers like the current Python //, so the result of the expression above is 0!
1.14. DECIMALS, FLOATS, AND FLOATING POINT ARITHMETIC 46

1.14.2. Exponentiation, Square Roots. Exponentiation is finding powers. In mathematical nota-


tion, (3)(3)(3)(3) = 34 = 81. In Python there is no fancy typography with raised exponent symbols like the
4, so Python uses ** before a power: Try in the Shell:
3**4
5*2**3
If you expected 1000 for the second one, remember exponentiation has even higher precedence than multi-
plication and division: 2**3 is 2*2*2 or 8, and 5*8 is 40.
Exponents do not need to be integers. A useful example is the 0.5 power: it produces a square root. Try
in the Shell:
9**.5
2**.5
The result of a power operation is of int type only if both parameters are integers and the correct result is
an integer.

1.14.3. String Formats for Float Precision. You generally do not want to display a floating point
result of a calculation in its raw form, often with an enormous number of digits after the decimal point, like
23.457413902458498. You are likely to prefer rounding it to something like 23.46. There are two approaches.
First there is a format function (not method) with a second parameter allowed to specialize the formatting
of objects as strings.. Read the following example interpreter sequence showing possibilites when a float is
being formatted:
>>> x = 23.457413902458498
>>> format(x, ’.5f’)
>>> ’23.45741’
>>> format(x, ’.2f’)
>>> ’23.46’
Note that the results are rounded not truncated: the result to two places is 23.46, not 23.45. The formatting
string ’.5f’ means after the decimal point round to 5 places. Similarly ’.2f’ means round to two decimal
places.
This rounding notation can also be placed after a colon inside the braces of format strings, for use with
the string format method. Read the Shell session:
>>> x = 2.876543
>>> ’longer: {x:.5f}, shorter: {x:.3f}.’.format(**locals())
>>> ’longer: 2.87654, shorter: 2.877.’
The colon separates the symbol identifying what value to use for the substitution from the instructions for
the specific formating method.
The colon and formatting instructions can also be used with the format versions depending on the order
of the parameters. Continuing the earlier Shell example:
>>> ’No dictionary: {:.5f}.’.format(x)
>>> ’No dictionary: 2.87654.’
There are many more fancy formatting options for the string format method that we will not discuss.
Going to the opposite extreme, and using formatting with many digits, you can check that Python does
not necessarily remember simple decimal numbers exactly:
>>> format(.1, ’.20f’)
’0.10000000000000000555’
>>> format(.2, ’.20f’)
’0.20000000000000001110’
>>> format(.1 + .2, ’.20f’)
’0.30000000000000004441’
>>> format(.3, ’.20f’)
’0.29999999999999998890’
>>>
1.15. SUMMARY 47

Python stores the numbers correctly to about 16 or 17 digits. You may not care about such slight errors,
but you will be able to check in Chapter 3 that if Python tests the expressions .1 + .2 and .3 for equality,
it decides that they are not equal! In fact, as you can see above, the approximations that Python stores for
the two expressions are not exactly equal. Do not depend on the exactness of floating point arithmetic, even
for apparently simple expressions!
The floating point formatting code in this section is also in example program floatFormat.py.

Exercise 1.14.3.1. * Write a program, discount.py, that prompts the user for an original price and
for a discount percentage and prints out the new price to the nearest cent. For example if the user enters
2.89 for the price and 20 for the discount percentage, the value would be (1- 20/100)*2.89, rounded to two
decimal places, 2.31. For price .65 with a 25 percent discount, the value would be (1- 25/100)*.65, rounded
to two decimal places, .49.10 Write the general calculation code following the pattern of the calculations
illustrated in the two concrete examples.

1.15. Summary
Section numbers in square brackets indicate where an idea was first discussed.
Where Python syntax is illustrated, the typeface indicates the the category of each part:
Typeface Meaning
Typewriter font Text to be written verbatim
Emphasized A place where you can use an arbitrary identifier. The emphasized text attempts to
be descriptive of the meaning of the identifier in the current context.
Normal text A description of what goes in that position, without giving explicit syntax
If there are several variations on a particular part of the syntax, alternatives will be show on successive
lines.
To emphasize the successive parts of the syntax, space will generally be left around symbol and punctu-
ation characters, but the space is not required in actual use.
(1) Python Shell
(a) A Shell window may be opened from the Idle menu: Run -> Python Shell [1.2.5]
(b) Entering commands:
(i) Commands may be entered at the >>> prompt. [1.4.1]
(ii) If the Shell detects that a command is not finished at the end of the line, a continuation
line is shown with no >>>. [1.4.2]
(iii) Statements with a heading ending in a colon followed by an indented block, must be
terminated with an empty line. [1.13.4]
(iv) The Shell evaluates a completed command immediately, displaying any result other than
None, starting on the next line. [1.4.1]
(v) The Shell remembers variable and function names. [1.6]
(c) An earlier Shell line may to copied and edited by clicking anywhere in the previously displayed
line and then pressing Enter.
(2) Idle editing
(a) Start a new window from the File menu by selecting New, Open..., or Recent Files. [1.9.1]
(b) Make your Python file names explicitly end with ’.py’ [1.6.1]
(3) To run a program from an Idle Editor Window:
(a) Select Run -> Run Module or press function key F5. The program runs in the Shell window,
after resetting the shell so all old names are forgotten. [1.9.1]
(i) If the program is expecting keyboard input, the text cursor should appear at the end of
the Shell history. If you somehow move the cursor elsewhere, you must explicitly move
it back. [1.9]

10In Python 3.0+, the previous expressions make sense, but in earlier versions of Python and in other languages like C++
and Java, where there are not separate division operators // and /, these expressions would be wrong because of the multiple
meanings of the operator / with different types. The expressions would work in these other languages if, for example, 100 were
replaced by 100.0.
1.15. SUMMARY 48

(ii) BUG WORKAROUND: If you were running a program that was expecting keyboard
input when you terminated it to start the latest run, you will need to start by pressing
the Enter key once or maybe twice to clear the old pending wait for input. [1.9.2]
(iii) Press Ctrl-C to stop a running program in a long or infinite loop.
(iv) After a program terminates, the Shell remembers function definitions and variable names
define outside of any function. [1.11.2]
(4) Errors come in three categories:
(a) Syntax errors: text that the interpreter recognizes as illegal when first reading it. This prevents
execution of your code. Python lets you know where it realized there was an error. Sometimes
this is the exact location, but the actual error could be anywhere earlier, often on the previous
line. [1.6]
(b) Execution errors: The first illegal action is detected while running your command or program.
The source of the error could be in the line where execution fails, or it could be an earlier
logical error that only later forces an execution error. [1.6]
(c) Logical errors: When Python detects nothing illegal, but you do not get the results you desire.
These errors are the hardest to trace down. Playing computer and additional print functions
help. [1.13.8]
(5) Type int, (short for integer):
(a) Literal integer values may not contain a decimal point. [1.14.1]
(b) Integers may be arbitrarily large and are stored exactly. [1.14.1]
(c) Integers have normal operations, with usual precedence (highest listed first):
(i) **: exponentiation (5**3 means 5*5*5) [1.14.2]
(ii) *, /,//, %: multiplication, division with float result, integer division (ignoring any re-
mainder), just the remainder from division [1.4.3]
(iii) +, -: addition, subtraction [1.4.1]
(6) Type float, (short for floating point): approximations of real numbers
(a) Literal values must contain a decimal point to distinguish them from the int type [1.14.1]
(b) Approximates a wide range of values [1.14.1]
(c) Does not dependably store numbers exactly – even numbers with simple decimal representation
[1.14.1]
(d) Has the same operation symbols as for integers [1.14.1]
(e) A mixed binary operation with an integer and a float produces a float result. [1.14.1]
(7) Type str, (short for string):
Literal values contain a sequence of characters enclosed in matching quotes.
(a) Enclosed in ’or ": The string must be on one line. [1.5.1]
(b) Enclosed in ’’’or """: The string may include multiple lines in the source file. [1.8.1]
(c) Escape codes inside literals include \’ for a single quote and \n for a newline. [1.8.2]
(d) Binary operations (operation symbols have the same precedence order as when the symbols
are used in arithmetic)
(i) stringExpression1 + stringExpression2
concatenation (running together) of the two strings [1.5.2]
(ii) stringExpression * integerExpression
integerExpression * stringExpression
Repeat the string the number of times given by the integer expression. [1.5.2]
(e) string format method:
(i) stringFormatExpression.format(parameter0, parameter1, parameter2, ...) [1.10.4]
where stringFormatExpression is any string with an arbitrary number of formatted sub-
stitutions in it. Formatted substitutions are enclosed in braces. A digit inside the braces
will indicate which parameter value is substituted, counting from 0. If digits are left out,
the format paramters are substituted in order. The expression inside the braces can end
with a colon (:) followed by a format specifying string such as:
.#f where # can be a non negative integer: substitute a numerical value rounded to the
specified number of places beyond the decimal point. [1.14.1]
1.15. SUMMARY 49

Example: ’A word: {}, a number: {}, a formatted number: {:.3f}.’.format(’Joe’,


23, 2.13579)
evaluates to: ’A word: Joe, a number: 23, a formatted number: 2.136.’
(ii) stringFormatExpression.format(**dictionary) The format expressions are the same
as above except that a key name from a dictionary appears inside the braces instead of
a digit. The dictionary referenced appears int he parameter list preceded by **. The
value to be substituted is then taken from the dictionary by accessing the key. Example:
If defs is a dictionary with defs[’name’] equaling ’Joe’, defs[’num’] equaling 23,
defs[’dec’] equaling 2.13579, then
’A word: {name}, a number: {num}, a formatted number: {dec:.3f}.’.format(**defs)
evaluates to the same string as in the previous example. [1.12.2]
(f) Strings are a kind of sequence.
(8) Type list
[ expression , expression , and so on ]
[ expression ]
[]
(a) A literal list consists of a comma separated collection of values all enclosed in square brackets.
There may be many, one, or no elements in the list. [1.13.2]
(b) A list is a kind of sequence, so it may be used as the sequence in a for-statement heading.
[1.13.4]
(9) Type dict (short for dictionary)
dict()
returns an empty dictionary
(a) A dictionary provides an association of each key to its value. The key can be any immutable
type, with includes numbers and strings. [1.12.1]
(b) dictName [ keyExpression ] = valueExpression
associates in the dictionary dictName the key derived from evaluating keyExpression with the
value derived from evaluating valueExpression. [1.12.1]
(c) Used in an expression, dictName [ keyExpression ] evaluates to the value in the dictionary
dictName coming from the key obtained by evaluating keyExpression. [1.12.1]
(10) Type of None: This literal value has its own special type. None indicates the absence of a regular
object.
(11) Identifiers
(a) Identifiers are names for Python objects [1.6.1]
(b) They may only contain letters, digits, and the underscore, and cannot start with a digit. They
are case sensitive. [1.6.1]
(c) You cannot use a reserved word as an identifier, nor are you recommended to redefine an
identifier predefined by Python. In the Idle editor you are safe if your identifier names remain
colored black. [1.6.1]
(d) By convention, multi-word identifiers either [1.6.1]
(i) use underscores in place of blanks (since blanks are illegal is identifiers), as in initial_account_balance
(ii) use camelcase: all lowercase except for the starting letter of the second and later words,
as in initialAccountBalance
(12) Variables are identifiers used to name Python data [1.6]
(a) When a variable is used in an expression, its latest value is substituted. [1.6]
(13) Statements
(a) Assignment statement: [1.6]
variable = expression
(i) The expression on the right is evaluated, using the latest values of all variables, and
calculating all operations or functions specified.
(ii) The expression value is associated with the variable named on the left, removing any
earlier association with the name.
(b) For-statement
for item in sequence :
1.15. SUMMARY 50

consistently indented statement block, which may use the variable item

For each element in the sequence, repeat the statement block substituting the next element
in the sequence for the name variable name item. See Programming Patterns for patterns of
use. [1.13.4]
(c) Return statement
return expression
This is used only in a function definition, causing the function to immediately terminate and
return the value of expression to the calling code, effectively acting as if the function call was
replaced by this returned value. [1.11.6]
(14) Function calls
functionName ( expression, expression, and so on )
(a) The number of expressions must correspond to a number of parameters allowed by the func-
tion’s definition. [1.11.4]
(b) Even if there are no parameters, the parentheses must be included to distinguish the name of
the function from a request to call the function. [1.11.2]
(c) Each expression is evaluated and the values are passed to the code for the function, which
executes its defined steps and may return a value. If the function call was a part of a larger
expression, the returned value is used to evaluate the larger expression in the place where the
function call was. [1.11.4]
(d) If nothing is returned explicitly, the function returns None.
(e) Function calls may also be used as statements, in which case any value that is returned is
ignored (except if entered directly into the shell, which prints any returned value other than
None).
(f) Keyword arguments are a special case. They have been used optionally at the end of the
parameter list for print.
(15) Functions that are built-in
(a) Print function: [1.7] [1.13.9]
print(expression)
print(expression, expression, expression)
print(expression, expression, expression, sep=stringVal, end=strVal)
print()
(i) Print the value of each expression in the list to the standard place for output (usually
the screen) separating each value by individual blanks unless the keyword argument sep
is specified to change it. There can be any number of expressions (not just 1 or 3 as
illustrated)
(ii) The string printed ends with a newline unless the keyword argument end is specified to
change it.
(iii) With no expression, the statement only advances to a new line.
(b) Type names can be used as function to do obvious conversions to the type, as in int(’234’),
float(123), str(123). [1.10.3]
(c) type(expression)
Return the type of the value of the expression. [1.5.1]
(d) input(promptString)
Print the promptString to the screen; wait for the user to enter a line from the keyboard,
ending with Enter. Return the character sequence as a string [1.10.1]
(e) len(sequence)
Return the number of elements in the sequence [1.3]
(f) range(expression)
Require expression to have a non negative integer value, call it n. Generate a sequence with
length n, consisting of the numbers 0 through n-1. For example range(4) generates the
sequence 0, 1, 2, and 3 [1.13.3]
(g) max(expression1, expression2, and so on)
Return the maximum of all the expressions listed. [1.3]
1.15. SUMMARY 51

(h) format(expression, formatString) [1.14.1]


If expression is numeric, the format string can be in the form ’.#f’, where the # gets replaced
by a nonnegative integer, and the result is a string with the value of the expression rounded
to the specified number of digits beyond the decimal point.
(16) Functions defined by a user:
def functionName ( parameter1, parameter2, and so on) :
consistently indented statement block, which may include a return statement
(a) There may be any number of parameters. The parentheses must be included even if there are
no parameters. [1.11.4]
(b) When a function is first defined, it is only remembered: its lines are not executed. [1.11.2]
(c) When the function is later called in other code, the actual parameters in the function call are
used to initialize the local variables parameter1, parameter2, and so on in the same order as
the actual parameters. [1.11.4]
(d) The local variables of a function are independent of the local names of any function defined
outside of this function. The local variables must be initialized before use, and the names lose
any association with their values when the function execution terminates. [1.11.8]
(e) If a return statement is reached, any further statements in the function are ignored. [1.11.6]
(f) Functions should be used to :
(i) Emphasize that the code corresponds to one idea and give an easily recognizable name.
[1.11.2]
(ii) Avoid repetition. If a basic idea is repeated with just the data changing, it will be easier
to follow and use if it is coded once as a function with parameters, that gets called with
the appropriate actual parameters when needed. [1.11.4]
(iii) It is good to separate the internal processing of data from the input and output of data.
This typically means placing the processing of data and the return of the result in a
function. [1.11.4]
(iv) Separate responsibilities: The consumer of a function only needs to know the name,
parameter usage, and meaning of any returned value. Only the writer of a function
needs to know the implementation of a function. [1.11.7]
(17) Modules (program files)
(a) A module may start with a documentation string. [1.9.4]
(b) Define your functions in your module. If the module is intended as a main program called only
one way, a convention is make your execution just be calling a function called main. [1.11.3]
(c) Avoid defining variable outside of your functions. Names for constant (unchanging) values are
a reasonable exception. [1.11.9]
(18) Documentation String: A string, often a multi-line (triple quoted) string that may appear in two
places:
(a) At the very beginning of a file: This should give overall introductory information about the
file [1.9.4]
(b) As the very first entry in the body of a function: This should describe: [1.12.1]
(i) The return value of the function (if there is one)
(ii) Anything about the parameters that is not totally obvious from the names
(iii) Anything about the results from the function that is not obvious from the name
(19) Programming Patterns
(a) Input-calculate-Output: This is the simplest overall program model. First obtain all the data
you need (for instance by prompting the user for keyboard input). Calculate what you need
from this data. Output the data (for instance to the screen with print functions). [??]
(b) Repetitive patterns: These patterns are all associated with loops. Loops are essential if the
number of repetitions depends on dynamic data in the program. Even if you could avoid a
loop by repeating code, a loop is usually a better choice to make the repetitive logic of your
program clear to all.
(i) Exact repetition some number of times: If the number of time to repeat is n:
for i in range(n):
actions to be repeated
1.15. SUMMARY 52

Here the variable i is included only because there must be a variable name in a for-loop.
[1.13.5]
(ii) For-each loop: Do the same sort of thing for each item in a specified sequence. [1.13.4]
for item in sequence :
actions to be done with each item
(iii) Successive modification loop: Repeat a basic idea, but where the data involved each
time changes via a pattern that is coded in the loop to convert the previous data into
the data needed the next time through the loop [1.13.6]:
initialize all variables that will be successively modified in the loop
loop heading for the repetition :
actions to be in each loop with the current variable values
modify the variable values to prepare for the next time through the loop
(iv) Accumulation loop: A sequence of items need to be combined. This works where the
accumulation of all the items can be approached incrementally, combining one after
another with the accumulation so far [1.13.7]:
initialize the accumulation to include none of the sequence
for item in sequence :
new value of accumulation =
result of combining item with last value of accumulation
(20) Playing computer: testing that you understand your code (and it works right or helping you find
where it goes wrong) [1.13.1,1.13.6, 1.13.8]
(a) Make sure line numbers are labeled
(b) Make a table with heading for line numbers, all variables that will be changing, and comments
(c) Follow the order of execution, one statement at a time, being careful to update variable values
and only use the latest variable values, and carefully following the flow of control through
loops and into and out of function calls.
CHAPTER 2

Objects and Methods

2.1. Strings, Part III


2.1.1. Object Orientation. Python is an object-oriented language. Every piece of data and even func-
tions and types are objects. The term object-oriented is used to distinguish Python from earlier languages,
classified as procedural languages, where types of data and the operations on them were not connected in the
language. The functions we have used so far follow the older procedural programming syntax. In the newer
paradigm of object-oriented programming, all data are in objects, and a core group of operations that can
be done on some particular type of object are tightly bound to the object and called the object’s methods.
For example, strings are objects, and strings “know how” to produce an uppercase version of themselves.
Try in the Shell:
s = ’Hello!’
s.upper()

Here upper is a method associated with strings. This means upper is a function that is bound to the string
before the dot. This function is bound both logically, and as we see in the new notation, also syntactically.
One way to think about it is that each type of data knows operations (methods) that can be applied to it.
The expression s.upper() calls the method upper that is bound to the string s and returns a new uppercase
string result based on s.
Strings are immutable, so no string method can change the original string, it can only return a new
string. Confirm this by entering each line individually in the Shell to see the original s is unchanged:
s
s2 = s.upper()
s2
s
We are using the new object syntax:
object.method( )
meaning that the method associated with the object’s type is applied to the object. This is just a special
syntax for a function call with an object.
Another string method is lower, analogous to upper, but producing a lowercase result.

Test yourself : How would you write the expression to produce a lowercase version of the string s? An-
swer:1 Try it in the Shell.

Test yourself in the Shell: How would you use this string s and both the lower and upper methods to
create the string ’hello!HELLO!’ ? Hint: 2 Answer: 3

Many methods also take additional parameters between the parentheses, using the more general syntax
object.method(parameters)
The first of many such methods we will introduce is count:
Syntax for count:
1s.lower()
2Use a plus sign to concatenate the pieces.
3s.lower() + s.upper()

53
2.1. STRINGS, PART III 54

s.count(sub)
Count and return the number of repetitions of a string sub that appear as substrings inside the string s.
Read and make sure you see the answers are correct:
>>> tale = ’This is the best of times.’
>>> tale.count(’i’)
3
>>> tale.count(’is’)
2
>>> tale.count(’That’)
0
>>> tale.count(’ ’)
5
There is a blank between the quotes in the line above. Blanks are characters like any other (except you can’t
see them)!
Just as the parameter can be replaced by a literal or any expression, the object to which a method is
bound with the dot may also be given by a literal, or a variable name, or any expression that evaluates to
the right kind of object in its place. This is true for any method call.
Technically the dot between the object and the method name is an operator, and operators have different
levels of precedence. It is important to realize that this dot operator has the highest possible precedence.
Read and see the difference parentheses make in the expressions:
>>> ’hello ’ + ’there’.upper()
’hello THERE’
>>> (’hello ’ + ’there’).upper()
’HELLO THERE’
To see if you understand this precedence, predict the results of each line and then test in the Shell:
3 * ’X’.count(’XXX’)
(3 * ’X’).count(’XXX’)
There are 0 ’XXX’s in ’X’, but 1 ’XXX’ in ’XXX’.
Python lets you see all the methods that are bound to an object (and any object of its type) with the
built-in function dir. To see all string methods, supply the dir function with any string. For example, try
in the Shell:
dir(’’)
Many of the names in the list start and end with two underscores, like __add__. These are all associated
with methods and pieces of data used internally by the Python interpreter. You can ignore them for now.
The remaining entries in the list are all user-level methods for strings. You should see lower and upper
among them. Some of the methods are much more commonly used than others.
Object notation
object.method(parameters)
has been illustrated so far with just the object type str, but it applies to all types. Later in the tutorial
methods such as the following will be discussed:
If seq is a list, seq.append(element) appends element to the end of the list.
If myData is a file, myData.read() will read and return the entire contents of the file....

2.1.2. String Indices. A string is a sequence of smaller components (individual characters), and it is
often useful to deal with parts of strings. Python indexes the characters in a string, starting from 0, so for
instance, the characters in the string ’computer’ have indices:
character c o m p u t e r
index 0 1 2 3 4 5 6 7
Each index is associated with a character, and you reference the individual characters much like in a
dictionary. Try the following. (You can skip the comments that make the indices explicit.) Enter in the
Shell:
2.1. STRINGS, PART III 55

# 01234567
s = ’computer’
s[0]
s[5]
s[8]
You cannot refer directly to a character that is not there. Indices only go to 7 in the example above.
Recall the len function, which gives the length of a sequence. It works on strings. Guess the following
value, and test in the Shell:
len(s)
A common error is to think the last index will be the same as the length of the string, but as you saw above,
that leads to an execution error. If the length of some string is 5, what is the index of its last character?
What if the length is 35?
Hopefully you did not count by ones all the way from 0. The indices for a string of length n are the
elements of the sequence range(n), which goes from 0 through n-1, or the length of the string minus one,
which is 5-1=4 or 35-1 = 34 in these examples.
Sometimes you are interested in the last few elements of a string and do not want to do calculations like
this. Python makes it easy. You can index from the right end of the string. Since positive integers are used
to index from the front, negative integers are used to index from the right end, so the more complete table
of indices for ’computer’ gives two alternatives for each character:
character c o m p u t e r
index 0 1 2 3 4 5 6 7
index from the right end -8 -7 -6 -5 -4 -3 -2 -1
Predict and test each individual line, continuing in the Shell:
s[-1]
s[-3]
s[-10]

it = ’horse’
len(it)
it[-1]
it[1]
Be careful - remember what the initial index is!

2.1.3. String Slices. It is also useful to extract larger pieces of a string than a single character. That
brings us to slices. Try this expression using slice notation, continuing in the Shell:
s[0:4]
Note that s[4] is the first character past the slice. The simplest syntax for a slice of a string s is:
s[startIndex : pastIndex]
This refers to the substring of s starting at index startIndex and stopping just before index pastIndex. It
confuses many people that the index after the colon is not the index of the final character in the slice, but
that is the system. Predict and try each line individually in the Shell:
s[2:5]
s[1:3]
If you omit the first index, the slice starts from the beginning. If you omit the second index, the slice goes
all the way to the end. Predict and try each line individually in the Shell:
s[:3]
s[5:]
Predict and try each line individually in the Shell:
word = ’program’
word[2:4]
word[1:-3]
2.1. STRINGS, PART III 56

word[3:]
word[3:3]
word[:1] + word[4:]
Python evaluates slices in a more forgiving manner than when indexing single characters. In a slice, if you
give an index past a limit of where it could be, Python assumes you mean the actual end. Predict and try
each line individually in the Shell:
word[:9]
word[8:10]
Enter a slice expression using the variable word from above that produces ’gra’.
A useful string method that uses the ideas of indices and slices is find.
Syntax options for find:
s.find(sub)
s.find(sub, start)
s.find(sub, start, end)
Return the integer index in the string s of the beginning of first complete occurrence of the substring sub. If
sub does not appear inside s, return -1. The value -1 would be an impossible result if sub were found, so if -1
is returned, sub must not have been found. If parameters start and end are not included in the parameter
list, the search is through the whole string s. If an integer value is given for start, the search starts at index
start. If an integer value is given for end, the search ends before index end. In other words if start and end
appear, then the search is through the slice s[start : end], but the index returned is still counted from the
beginning of s.
For example, check that the following make sense. The comment line is just there to help you count:
>>> # 01234567890
>>> s = ’Mississippi’
>>> s.find(’i’)
1
>>> s.find(’si’)
3
>>> s.find(’sa’)
-1
>>> s.find(’si’, 4)
6
Predict and try each line in the Shell:
# 0123456789012
line = ’Hello, there!’
line.find(’e’)
line.find(’he’)
line.find(’e’, 10)
line.find(’he’, 10)
We will consider more string methods later, but we can already do useful things with the ones introduced.
Inside the Shell, you can look up documentation on any of the methods listed with the dir function.
Here is a place that you want to refer to the method itself, not invoke the method, so note that you get
help for s.find not for s.find(). Assuming you defined the string s in the Shell earlier, try in the Shell
help(s.find)
The Python documentation uses square brackets to indicate optional elements that get a default value if you
leave them out. This shortens the syntax descriptions.
If you want method documentation when you do not have a variable of the type created, you can also
use the type name. Try in the Shell:
dir(str)
help(str.capitalize)
Indexing and slicing works on any kind of Python sequence, so you can index or slice lists also. Read this
Shell session:

You might also like