Chapter 2:
Arithmetic, variables, input, and output


2.1 Strings
2.2 Integer arithmetic
2.3 Variables: names for data
    2.3.1 Foundations: Variables accumulate knowledge
2.4 Garbage-in, garbage-out: Input and Output
2.5 Programs that use numerical input
    2.5.1 Printing numerical output
    2.5.2 Foundations: Input commands accept knowledge
2.6 Semantics of Commands
    2.6.1 Writing your own execution traces
2.7 Floats as inputs and outputs
2.8 Design: Algorithms
2.9 Design: How to design a program
    2.9.1 Practicing
    2.9.2 Planning
    2.9.3 Case study: Change-calculator program
    2.9.4 Testing
2.10 Summary of Python
    2.10.1 Constructing a Shortcut


My father used to call computer programming, ``garbage in, garbage out.'' What he meant to say is that a computer program works by accepting external, ``input'' knowledge, like numbers, which it uses to compute new, ``output'' knowledge, which it displays --- sensible input knowledge generates useful output knowledge; garbage input generates garbage output. In this lecture we learn to write programs in this classical, input-compute-output format. We learn the necessary liguistics and we encounter key design and foundational topics.

First, read Dawson, Chapter 2.


2.1 Strings

We begin with some details left over from Chapter 1: A sequence of letters, and in general, a sequence of symbols that you make by pressing keys at the keyboard, is a string. When writing in Python, we enclose strings by " pairs or by ' pairs, for example, "this is a string." and 'so is this!!!'

A string longer than one line is enclosed by """. Here is an example:

print """
+--+   +--+   +--+
|  |   |  |   |  |
|  +---+  |   |  |
|  +---+  |   |  |
|  |   |  |   |  |
+--+   +--+   +--+
"""
As the example suggests, we might use a multi-line string with a print command to print a pattern in the command window. (Try it --- Place the above command into a file, named TestString.py, within folder C:\MyPython, and test the program from a new command window:
set path=C:\Python22
cd C:\MyPython
python TestString.py
(Note: if you correctly set the Path variable, as described at the end of the previous chapter, you won't need the first command.)

You can also write the above command like this:

print \
"""
+--+   +--+   +--+
|  |   |  |   |  |
|  +---+  |   |  |
|  +---+  |   |  |
|  |   |  |   |  |
+--+   +--+   +--+
"""
where the \ indicates that the rest of the command is continued on the next line. The backslash can also be used to split a long command across two lines, e.g.,
print  1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 \
       + 10 + 11 + 12 + 13
which prints the sum, 91.

Finally, we can print together strings and numbers on the same line if we separate them by commas. Here is an example:

print "The sum of", 3, "and", 2, "is", (3+2)
which prints
The sum of 3 and 2 is 5
(Notice that the arithmetic expression, (3+2), was computed to its answer.)

We can use the commas to split the print commands across multiple lines like this:

print "The sum of",
print 3, "and", 2,
print "is",
print  3 + 2
Place these commands in a program, say, Test.py, and try it --- python Test.py. You will again see
The sum of 3 and 2 is 5


2.2 Integer arithmetic

A computer's CPU is wired to do integer arithmetic, and we can use ordinary arithmetic notation in Python to tell the computer to calculate arithmetic. Here is the grammatical syntax of arithmetic: Next, here are some Python experiments, which we can do by starting the Python interpreter and talking to it directly: (Remember that we can do this by opening a new command window and typing, set path=C:\Python22 and then python.)
>>> print 2 * 3 * 4
24
>>> print  9 / 4
2
>>> print 9 % 4
1
>>> print 2 - 3 - 4
-5
>>> print  2 * (3 + 4)
14
>>> print (2 * 3) + 4
10
>>> print 2 - (3 - 4)
3
In the second experiment, notice that the remainder is forgotten; in the third, it is the remainder that is retained. (9 divided by 4 has answer 2 with remainder 1.) The remaining experiments show that it is important to use parentheses to indicate the order in which the arithmetic operators should be performed.

Python lets us do arithmetic with fractions, which are called floats (floating-point numbers). We must type fractional numbers to indicate we are working with floats. Here are examples:

>>> print 2.0 * 3.0
6.0
>>> print 1.0 / 3.0
0.33333333333333331
>>> print  2.0 * 3.3
6.5999999999999996
>>> print 9.0 / 4.0
2.25
>>> print 9 / 4.0
2.25
>>> print 9.00 / 4
2.25
The computer's CPU cannot do exact fractional arithmetic; for example, we know that 1.0/3.0 is the infinite fraction of 3s, 0.333333333333333333333...3...., but the size of numbers stored in a computer limits how precise the result can be. (This situation can prove frustrating and even disastrous when precise answers are required, e.g., for the Mars-rover launched from Earth that crash landed due to an arithmetic imprecision.) There are also surprises, like that shown in the third example. The remaining examples show that division on fractional numbers produce fractional answers.

It is possible to mix ints and floats in the same expression, and the result is computed as a float. For example,

>>> print 1.0 / 3
0.33333333333333331
because the 3 is converted to 3.0 for doing the division.


2.3 Variables: names for data

In algebra class, we learned how to write equations that define important ideas. For example, to convert from hours to minutes, we write
minutes = hours * 60
and we can use the laws of algebra to compute that 4 hours contains 240 minutes:
hours = 4
minutes = hours * 60
implies that
minutes = 4 * 60 = 240

Names like minutes and hours are called variables in algebra (the number with which we replace the name can ``vary''), and variables are used in Python as well. Indeed, we can write the equations verbatim in Python like this:

>>> hours = 4
>>> minutes = hours * 60
>>> print hours, "hours has", minutes, "minutes"
4 hours has 240 minutes
The equational commands are called assignments (``the value 4 is assigned to variable hours.'') The second command, another assignment, computes the number represented by the expression, hours * 60. Since hours names 4, the expression computes to 240. The third command asks Python to display the integer computed for variable minutes. Try it.

Here is a second example, using strings:

>>> s = "ha"
>>> t = s + s + s
>>> print t
'hahaha'
Finally, here is an equation that converts degrees celsius (centigrade) to fahrenheit, using fractional numbers:
fahrenheit = (1.8 * celsius) + 32.0

One important feature of variables used in computer programs is that a variable may obtain a value and later have that value forgotten (``overwritten'') by another value. Here is an example:

hours = 4
minutes = hours * 60
print hours, minutes
hours = 5
minutes = hours * 60
print hours, minutes
These commands (clumsily) compute the minutes within 4 hours and 5 hours by using variables hours and minutes to do two calculations. The program will display
4 240
5 300
When hours = 5 is computed, the 4 is forgotten (overwritten) by 5. The 4 is lost forever. A similar phenomenon occurs when the second assignment, minutes = hours * 60 is computed: 240 is overwritten by 300 and is lost forever.

You should take great care when overwriting variables with new values. This action complicates our understanding of the knowledge generated by the program. We now study precisely this issue.


2.3.1 Foundations: Variables accumulate knowledge

Computer programs instruct a computer how to generate new knowledge. In the previous chapter, we noted that a print command displays knowledge the computer generated. Now, an assignment command names knowledge that has been computed.

Let's return to this example,

hours = 4
minutes = hours * 60
print hours, "hours has", minutes, "minutes"
and consider the knowledge that is generated and named by each command. The first command, hours = 4, of course generates the knowledge that there are 4 hours:
hours = 4
# assert: hours = 4
minutes = hours * 60
print hours, "hours has", minutes, "minutes"
We have inserted a comment line to summarize the knowledge that is generated and named. We call this an assertion, because we assert or predict the consequences of the command.

Consider the next command:

hours = 4
# assert: hours = 4
minutes = hours * 60
# assert: hours = 4  and  minutes = hours * 60
print hours, "hours has", minutes, "minutes"
The second assignment command establishes an algebraic equality, and with our knowledge of algebra, we conclude one more important fact:
hours = 4
# assert: hours = 4
minutes = hours * 60
# assert:  hours = 4  and  minutes = hours * 60
# implies: minutes = 240
print hours, "hours has", minutes, "minutes"
Using a tiny bit of algebra, we calculate that minutes = 4 * 60, which implies that minutes = 240. The assertions and their implications make us confident that the program will indeed display
4 hours has 240 minutes
when it is computed.

We can draw the program as a ``straight-line circuit'' and annotate it with the assertions:


Here is a second example: Here again is the equation for converting a celsius temperative to fahrenheit:

fahrenheit = (1.8 * celsius) + 32.0
Say that we do not know the value of celsius, other than it is above 0 (that is, above freezing). We can use our knowledge of algebra like this:
# assert: celsius > 0
fahrenheit = (1.8 * celsius) + 32.0
# assert:  celsius > 0  and  fahrenheit = (1.8 * celsius) + 32.0
# implies: fahrenheit > 32.0
because 1.8 * celsius > 1.8 * 0, implying that (1.8 * celsius) + 32.0 > (1.8 * 0) + 32

This example shows the form of reasoning that all skilled software engineers apply on a daily basis. Although we do not know the exact number that will be used for the celsius temperature, we already understand the nature of the knowledge generated by the computation --- temperatures above freezing in celsius (0) generate temperatures above freezing in fahrenheit (32):


Here is a third example, which illustrates how knowledge can be lost during a computation:

hours = 4
minutes = hours * 60
print hours, minutes
hours = 5
minutes = hours * 60
print hours, minutes
This example was developed in the previous section, when we noted that a variable can acquire a new value during a computation that overwrites its previous value. After the first two commands, we have the expected consequences:
hours = 4
# assert:  hours = 4
minutes = hours * 60
# assert:  hours = 4  and  minutes = hours * 60
# implies:  minutes = 240
print hours, minutes

hours = 5
minutes = hours * 60
print hours, minutes
What is the knowledge accumulated after we print hours and minutes and then reset hours = 5 ? Clearly it is not
hours = 4  and  minutes = hours * 60  and  minutes = 240  and  hours = 5
This is a mathematical contradiction! Some knowledge is lost when the 4 assigned to hours is overwritten by 5. To see precisely which facts are lost, we restate the knowledge, annotating the facts that were true for the old value of hours and for the new value of hours:
hours_old = 4
minutes = hours_old * 60
minutes = 240
hours_new = 5
All facts that mention hours_old must be forgotten. This gives us
minutes = 240
hours_new = 5
Now we drop the subscript, new, and this yields the correct knowledge at this point in the computation:
hours = 4
# assert:  hours = 4
minutes = hours * 60
# assert:  hours = 4  and  minutes = hours * 60
# implies:  minutes = 240
print hours, minutes

hours = 5
# assert: minutes = 240  and  hours = 5    <-- CORRECT !
minutes = hours * 60
print hours, minutes
Notice that there is no algebraic relationship between the numbers named by minutes and hours at this point.

When we finish our analysis, we determine that the knowledge resulting from the final assignment is

minutes_old = 240
hours = 5
minutes_new = hours * 60
We forget the out-of-date fact that minutes_old = 240, giving us
# assert: minutes = 240  and  hours = 5
minutes = hours * 60
# assert: hours = 5  and  minutes = hours * 60
# implies: minutes = 300
print hours, minutes
Here is the example restated as a ``straight-line'' circuit:

Exercises

Use algebra to calculate the knowledge accumulated after each command in the following programs:
  1. celsuis = 20
    fahrenheit = (1.8 * celsius) + 32.0
    
  2. # assert: hours > 1  and  hours < 10
    minutes = hours * 60
    
  3. y = x
    x = x + 1
    
    Can you deduce that y < x at the end? Can you deduce that x = y + 1 at the end?


2.4 Garbage-in, garbage-out: Input and Output

Algebraic equations, like
minutes = hours * 60
and
fahrenheit = (1.8 * celsius) + 32.0
define little recipes for calculation, and we saw in the previous sections how to use such equations in Python programs that calculate and print answers, e.g.,
hours = 4
minutes = hours * 60
print hours, minutes
But what if we want to calculate how many minutes are in 6 hours? 24? 48? Rather than constantly edit the program, inserting new numbers for the value of hours, we can rewrite the Python program so that it asks its human user to type the number of hours that must be converted into minutes. The information typed by the user is input to the program.

Here is a first, tiny example: Say that we write a script (program) that repeats three times a string we type. When the program, named Triple.py, is started, it asks the user to type some text (a string):

$ python Triple.py
Type any string you wish:
Perhaps the user types hey! followed by the Enter key. We see this:
$ python Triple.py
Type any string you wish: hey!
hey!hey!hey!
(Note: from now on, we use a dollar sign, $, to stand for the prompt we see within a command window. Or, you can start a program by double-clicking on its icon.) When we typed hey!, we supplied input, and when the answer appeared, it was output. Input and output are data (information used by the program). Here is the program, Triple.py:
====================================

# Triple repeats a string three times.

phrase = raw_input("Type any string you wish: ")
tripled = phrase + phrase + phrase
print tripled

raw_input("\n\npress Enter to finish")

=========================================
The first line is a comment, which reminds us and tells others what the script means to do. The second line is blank, and the third,
phrase = raw_input("Type any string you wish: ")
is a Python command that
  1. displays the string, Type any string you wish:
  2. waits for the user to type some symbols and press the Enter key
  3. grabs the typed symbols, makes a string of them, and names the string phrase.
raw_input is called a function; it is a self-contained, ``mini-program'' that you can use by stating its name. The function has an argument, here, "Type any string you wish: ", that the function (mini-program) uses as its input to do its own mini-computation. The mini-computation is outlined in Steps 1-3 just listed above.

The next command makes three copies of the string named phrase, appends them, and names the new string tripled. The command thereafter displays string tripled.

The final command is Dawson's trick that pauses the program and asks us to press the Enter key one last time before the program finishes. (This trick is useful when we start the program by double clicking on its icon in a File Window.)

Notice that we can use the script as often as we like; here's another go:

$ python Triple.py
Type any string you wish: Ha
HaHaHa
Each time, the program receives input and produces output based on the input.

Say that we rewrite the script like this and name it TripleShout.py:

================================

# TripleShout  repeats a string three times, but in upper-case letters.

phrase = raw_input("Type any string you wish: ")
phrase = phrase.upper()   # .upper is a _method_ 
tripled = phrase + phrase + phrase
print tripled
raw_input("\n\npress Enter to finish")

=====================================
When you use this, you might see
$ python TripleShout.py
Type any string you wish: hey!
HEY!HEY!HEY!
The alteration is this new command:
phrase = phrase.upper()   # .upper() is a _method_ 
As the comment says, the new concept is .upper(), which is called a method. For now, think of methods as arithmetic operations. Here, .upper() is an operation on the string named phrase, which computes a new string that has all upper-case letters. The upper-case string is then renamed phrase (and the old meaning of phrase is lost forever). We will say more about this behavior later.

Method .upper() is also a function, and you are welcome to ``read'' phrase.upper() as the function, upper(phrase). Function upper makes a new string that looks like the string named by phrase, but with upper-case letters. (We will learn later in the course the reasons why a ``method'' is written differently from a ``function'' in Python.)


2.5 Programs that use numerical input

Say that we write a script (program) that tells us how many minutes are in some hours. The program is named HoursToMinutes.py, and we would use it like this:

$ python HoursToMinutes.py
Please type an hours amount, a nonnegative int: 4
The number of minutes is 240 .
That is, we start the script, and it asks us
Please type an hours amount, a nonnegative int:
So, we type a number, say 4, and press Enter. The answer appears:
The number of minutes is 240 .
Here, 4 is the input, and The number of minutes is 240 . is the output. Here is the script, HoursToMinutes.py:
FIGURE========================================

# HoursToMinutes
# This program converts hours to minutes.
#   assumed input: hours - a nonnegative integer
#   guaranteed output: the conversion of hours to the corresponding amount
#                      of minutes, a nonnegative integer

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
minutes = hours * 60
print "The number of minutes is", minutes, "."

raw_input("\n\npress Enter to finish")

ENDFIGURE===============================================
The first five lines are comments that explain the program's name and its purpose. Lines 3-5 summarize the program's input and output behavior and state a guarantee about the kind of output the program will produce, assuming that the input is correctly entered.

Such comments are crucial for packaging and selling the program to others. For example, if someone tries to supply a word as input, we see

$ python HoursToMinutes.py
Please type an hours amount, a nonnegative int: four
Traceback (most recent call last):
  File "HoursToMinutes.py", line 7, in ?
    hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
ValueError: invalid literal for int(): four
The program did not behave as guaranteed because its input failed the assumption. Instead, we received as output a complicated explanation that the program's Line 7 did not operate properly and the program stopped there with a ValueError (whatever that is!).

Returning to the program, we see that lines 7-9 receive the input, compute the answer, and print it:

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
minutes = hours * 60
print "The number of minutes is", minutes, "."
Note that

You should experiment with this script: Try it with different inputs (say, 660 or 0 or -12 or Help!). Next, edit the file HoursToMinutes.py and alter its commands: add spaces or remove them; add blank lines or remove them; place comments in new places. Also, remove the commas in Line 9 and see what happens when you use the script. Change the name, hours to HOURS or fred or hours12 or 12hours.

Some of these changes will cause the script to misbehave; others won't. Look at the error messages that result from using a badly written script. These experiments are exposing the meaning of semantics of the fundamental Python commands.

Here is the conversion of Celsius temperatures to Fahrenheit, written as a program:

=============================

# CtoF
#  Converts Celsius to Fahrenheit
#  assumed input: celsius - an integer (whole number)
#  guaranteed output: the corresponding amount in fahrenheit degrees

celsius = int(raw_input("Type Celsius degrees, an int: "))
fahrenheit = ((9.0/5.0) * celsius) + 32.0   # note the fractions!
print "The corresponding temperature in Fahrenheit is", fahrenheit

raw_input("\n\npress Enter to finish")

===================================
You can test it:
$python CtoF
Type Celsius degrees, an int: 22
The corresponding temperature in Fahrenheit is 71.599999999999994


2.5.1 Printing numerical output

The simplest way of printing numbers is placing them on the same line, separated by commas, within a print command, say like this:
dollars = 49
cents = 95
print "$", dollars, ".", cents
This prints
$ 49 . 95
For better or for worse, the extra spaces appear. There is a trick to eliminate the spaces: The Python operation, str, converts a number to a string, so that the string can be appended to another string without any intervening spaces. Try this:
dollars = 49
cents = 95
print "$" + str(dollars) + "." + str(cents)
This prints
$49.95
because its appends together "$" + "49" + "." + "95".


2.5.2 Foundations: Input commands accept knowledge

A program receives knowledge from its user, the human, by means of the raw_input command. The program uses knowledge conveyed by the input data to generate new knowledge, which the program displays via print commands.

Consider again the program that converts hours into minutes. It is shown here with the assertions that indicate the knowledge generated in the course of the computation:

=====================================================

# HoursToMinutes
# This program converts hours to minutes.
#   assumed input: hours - a nonnegative integer
#   guaranteed output: the conversion of hours to the corresponding amount
#                      of minutes, a nonnegative integer

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
# assert: hours >= 0     ( >=  means ``greater-than-or-equals'')
minutes = hours * 60
# assert: hours >=0  and  minutes = hours * 60
# implies:  minutes >= 0
print "The number of minutes is " + str(minutes) + "."

raw_input("\n\npress Enter to finish")

========================================================
Our analysis of the program's computation shows that the minutes that are printed are indeed a nonnegative integer, provided that the input is a nonnegative integer.

As we well know, people often fail to read instructions, and there might well be someone who tries something silly, like this:

$ python HoursToMinutes.py
Please type an hours amount, a nonnegative int: -6
The number of minutes is -240.
The output is inappropriate (``garbage'') because the input was garbage.

The Python language lets us insert an assertion into a program and enforce it as a safety check while the program computes. We do it like this:

FIGURE==================================================

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))

assert hours >= 0   # this assert will be checked while the program executes!

minutes = hours * 60
print "The number of minutes is " + str(minutes) + "."

raw_input("\n\npress Enter to finish")

ENDFIGURE==================================================

The command,

assert hours >= 0
is checked by the computer immediately after the hours are received. If the value assigned to hours is indeed nonnegative, the program proceeds as intended with no interruption. But if hours's value is negative, the program halts with an assertion error.

Here is a example of an assertion error:
$ python HoursToMinutes.py
Please type an hours amount, a nonnegative int: -6
Traceback (most recent call last):
  File "HoursToMinutes.py", line 4, in ?
    assert hours >= 0  # this assert will be checked while the program executes!
AssertionError

It is a good idea to insert assert commands when the correct behavior of the program depends on correct input values. It is unnecessary (but causes no harm) to add additional asserts:

=========================================================

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
assert  hours >= 0
minutes = hours * 60
assert  hours >=0  and  minutes == hours * 60  # note that == means ``equals''
assert  minutes >= 0
print "The number of minutes is " + str(minutes) + "."

===========================================================
The additional asserts are unncessary because our algebraic calculations guarantee that, if the input is nonnegative, the remainder of the program behaves correctly.

In practice, a software engineer might not have adequate time to calculate the precise knowledge generated at all key places within a huge program. In this situation, the software engineer inserts assert commands to monitor and verify that the program is operating with appropriate knowledge at the key places. We will use assert commands in this way in later examples in these notes.


2.6 Semantics of Commands

By reading and trying the example programs, you have obtained some basic knowledge of what the computer does when it must execute a Python program. But we must become more expert at understanding what happens when a Python program is started and the CPU does its instructions. That is, we must learn the semantics (meanings) of Python commands.

When you first start your computer, it looks like this:


The start-up program, the operating system (OS), rests in primary storage, and the CPU reads and does the instructions of the OS. (The instructions are commands like, ``redraw the pictures on the display,'' ``see what that mouse click is about,'' ``make the clock move forward by one second,'' and so on.)

Say that you start a python program; the OS reads your request and tells the CPU to do these steps:

  1. Reserve some of the unused part of primary storage (a storage partition) to hold your program.
  2. Copy the Python interpreter from disk into the storage partition. (Recall that the Python interpreter is a converter (translator) program that helps convert Python instructions into the machine language of the CPU.)
  3. Copy the program you want executed into the storage partition.
  4. Reserve a namespace in the storage partition. The namespace holds all the variables and values that are created by the Python program --- it holds the knowledge generated by the program.
The computer now looks like this:

Notice that the Python interpreter has a variable of its own --- the instruction counter (i.c.), which remembers which line of the Python program must be executed next.

Let's follow the semantics of the example program. Line 7 is

hours = int( raw_input("Please type an hours amount, a nonnegative int: "))
To execute the assignment, the Python interpreter triggers these steps:
  1. The namespace is checked to see if the left-hand side, hours, exists. Here, it does not, so a cell is created for it. There is no value for the cell just now:
    
    
  2. Function raw_input is started, and it displays the string on the display. The user types a string that is supposed to look like an integer, and presses return. This string is the answer computed by the function. So, if the user presses 4, the string, "4" is the answer.
    
    
  3. Function int is started, and it uses the string to make an integer. So, "4" is converted into the number, 4, inside the computer, and this is the answer computed by int.
    
    
  4. The integer is assigned to name hours in the namespace.
    
    
The namespace now contains a cell named x, which holds the 4. Notice that the instruction counter moves to 8.

Line 8 computes the assignment,

minutes = hours * 60
which creates a second variable cell in the namespace:

Next, the phrase, hours * 60 is computed: The name, hours, is located in the namespace, and the number in its cell is extracted:
 
Next, the arithmetic is calculated, and the answer is stored into the cell named hours:

Finally,

print "Minutes are", minutes
looks at the value of minutes in the namespace and displays it:

Notice that print is itself another function, whose job is to compute some text and display it. print's argument comes immediately after the word, print, and there is no need for matching parentheses. (Sorry for this inconsistency --- usually a function's argument is bracketed by parentheses.)

Now, the above pictures look different from the ones we saw in the chapter about Computer Architecture --- where are the computer words that were mentioned in the earlier chapter? The answer is that the OS instructions are copied into some computer words, and the instructions of the Python interpreter are copies into some computer words, and the Python interpreter's instruction counter (i.c.) is itself a number that is copied into a computer word.

The Python program is copied into some computer words, and the namespace is a large area of empty computer words. When a variable is assigned, like hours = 4, one computer word holds the name, hours, and one computer word holds the integer, 4. So, the ``cells'' mentioned in the above explanation are computer words.

Now that we know how variables and their values are remembered in computer storage, we can study tricky sequences of commands. First, what if the previous example program was modified to look like this:

hours = 4
minutes = hours * 60
print minutes
hours = 5
minutes = hours * 60
print minutes
We know that the program should print 240 and then 300, but now we can understand why: after the cell named hours is set to 4 and minutes's cell is set to 240 and printed, we have this namespace:
hours = 4
minutes = hours * 60
print minutes

The fourth command destroys the value in hours's cell, replacing it by 5:
hours = 5

The fifth command computes hours * 60 and placed the answer in minutes's cell, destroying the old value:
minutes = hours * 60

The example shows that an assignment command always places a value in a variable's cell, destroying what was there before. In this sense, assignment commands are different from algebraic equations, where there is no notion of ``changing'' the value of a variable.

Here is a second example:

x = 2
x = x + 1
When the program starts, the namespace is empty:
x = 2
x = x + 1
              
When x = 2 is computed, a cell is created for x:
x = 2
       
x = x + 1
and then 2 is stored in it:
x = 2
          # assert: x = 2
x = x + 1
(Notice how the namespace holds the generated knowledge.)

Next, the command x = x + 1 begins by checking if there is a cell for the variable on the left-hand side, x. (There is.) Next, the expression x+1 computes to 3, and 3 is inserted into x's cell:

x = 2
x = x + 1
            # assert: x_old = 2  and  x_new = x_old + 1
                                         # implies:  x_new = 3
# implies: x = 3
The example shows how the namespace uses the ``old'' value of a variable to generate a ``new'' one --- the assignment resets the value in the cell in the namespace.

Here is another example. Say we have a program with just this one command:

x = x + 1
As before, the namespace starts empty:
 
x = x + 1 
           
and the assignment statement executes. First, since there is no cell for x, one is created in the namespace:
x = x + 1 
           
Next, x + 1 is computed. But when the value for x is fetched, nothing is found in the cell. The Python interpreter prints this error message and halts:
>>> x = x + 1
Traceback (most recent call last):
  File "", line 1, in ?
NameError: name 'x' is not defined
Our careful reading of the semantics of assignment shows us that a variable cannot be used in an expression if it does not already have a value in its cell in the namespace.


2.6.1 Writing your own execution traces

When we write a sequence of diagrams that shows how the computer executes a program, we are writing an execution trace.

Writing a program's execution trace is the best way of understanding what the program does. This is not only useful for understanding a program someone else has written, but also for checking your own programming work and explaining it to others.

A quick way of writing an execution trace starts like this:

  1. On one sheet of paper (or on your computer's display!), write the program and place numbers by each command. (These are the ``instruction numbers.'')
  2. On a sheet of paper, make a box for the instruction counter, and start it at the number of the first command.
  3. On the same sheet, make a (big) box for the namespace
  4. On the same sheet, make a box that represents the display, where print statements will print their data.
  5. Now, ``play computer,'' and execute the program with the sheet of paper and a pencil.
For practice, here the example program's trace once more. The program with its instruction numbers looks like this:
hours = int( raw_input("Please type an hours amount: "))  #7
minutes = hours * 60  #8
print "The number of minutes is", minutes, "."  #9
Our sheet of paper is grouped into three columns, like this:
i.c.    namespace          display
-----+-------------------+---------
 7   |                   |
We ``play computer'' and execute command 7:
i.c.    namespace          display
-----+-------------------+---------
 X7  |  hours : 4        | Please type an hours amount: 4
 8      
We have recorded that a message appeared on the display, the human typed input 4, and a variable named hours was constructed in the namespace. The next command is at line 8. When we execute it, the execution trace is modified to this:
i.c.    namespace          display
-----+-------------------+---------
 X7  |  hours : 4        | Please type an hours amount: 4
 X8  |  minutes : 240    |
  9  |
and after command 9 finishes, we are done:
i.c.    namespace          display
-----+-------------------+---------
 X7  |  hours : 4        | Please type an hours amount: 4
 X8  |  minutes : 240    |
 X9  |                   | The number of minutes is 240 .
Computer traces will be valuable to us in the near future.


2.7 Floats as inputs and outputs

Floats (fractional numbers) can be inputs and outputs. For practice, study and use this script:

=============================

# CtoF
#  Converts Celsius to Fahrenheit
#  assumed input: celsius - a fractional number
#  guaranteed output: the corresponding amount in fahrenheit degrees

celsius = float( raw_input("Type Celsius degrees, a fraction: "))
fahrenheit = ((9.0/5.0) * celsius) + 32.0   # note the fractions!
print "The corresponding temperature in Fahrenheit is", fahrenheit

raw_input("\n\npress Enter to finish")

===================================
This program looks lots like the ones seen earlier; the only new idea is the conversion operator, float( .... ), which makes a string that looks like a fractional number into a float.

We can test it:

$python CtoF
Type Celsius degrees, a fraction: 20.2
The corresponding temperature in Fahrenheit is 68.36


2.8 Design: Algorithms

A cookbook recipe looks a bit like a computer program: it uses ingredients (data) and gives commands, that when followed, compute the output (something to eat).

The recipe is an algorithm --- a sequence of commands that accomplish a goal. Algorithms are also used in computing:

an algorithm is a design or an outline of the program we must write.

Algorithms often follow a standard pattern or format. For example, the standard algorithmic pattern we have used in this lecture goes like this:

  1. read the input data
  2. compute the answer from the data
  3. display the answer as output
As simple as this algorithmic pattern might be, it forms the basis of many standard computer programs. For example, when you use a web form to order a book, you fill in the order data, press the Send button, and after a bit, you see a confirmation that your order has been placed. Behind the web form, there was a computer program whose algorithm had the pattern just shown.

Also, a text editor or a spreadsheet program uses the standard algorithmic pattern, and the key idea is that it uses the pattern over and over again, each time the user inserts a new number into a cell of the spreadsheet or the user inserts a new line of text into the edited document.


2.9 Design: How to design a program

When writing a Python program, we do not just start writing Python commands --- some practicing and planning are required.


2.9.1 Practicing

Programming is really ``teaching'' the computer how to do something. Before you can teach the computer to do something, you must know, really well, how to do that same thing yourself. So, when you want to teach the computer to do a job,
you must practice doing the job yourself, say, with pencil and paper, until you understand ``inside and out'' how to do the job
By practicing the job over and over, you will observe and learn the underlying pattern of steps that one must do. Only then are you ready to teach the steps to someone or something else.

For example, if you practice converting celsius temperatures to fahrenheit temperatures often enough, you will learn the correct pattern of arithmetic and you will be able to explain it to someone else (or a computer).


2.9.2 Planning

It is easier to teach someone how to do a job by showing them in person than by writing down the steps for them to read. But when we teach a computer how to do a job, we are forced to write down all the steps: Computers learn only through reading the programs we write for them.

We cannot write a program in English words and pictures; we must use a programming language, like Python, which forces us to ``talk'' in a stilted way. It is difficult to explain our ideas correctly in a programming language, but there is a standard list of steps that we can follow that leads us to writing correct programs:

  1. describe the program's intended behavior
  2. design the program's algorithm
  3. write the program based on the algorithm and test it
  4. document your work with assume-guarantee conditions and asserts
The first step we learn from our practicing. The second step is our attempt to explain in English words what we did when we practiced. The third step is our conversion of English into Python. And the last step is to help us remember in the future what we did.

Let's consider each stage within an example.


2.9.3 Case study: Change-calculator program

Stage 1. describe behavior: Say that you want a program that adds up the value of the coins in your pocket.

How would you add the coins in your pocket? If you practice this awhile, you quickly learn that you total the quarters, add to this the total of the dimes, then the nickels, then the pennies. Now, you must explain to the computer the technique you practiced and learned.

You begin by asking how the computer will behave when someone asks it to add up some coins. For the change-making program, we might expect the computer to interact with the human like this:

How many quarters? (you type here, say, 9)
How many dimes?  (you type, say, 3)
How many nickels? (you type, say, 0)
How many pennies? (you type 212)
The total is 4 dollars and 67 cents.
Have a nice day.
This one example of the computer doing the job is called a scenario or use-case. You should plan out several of these scenarios that show how the computer should act. Once you have these, you can start planning the steps the computer takes to generate the behaviors in the scenarios.

Stage 2. design the algorithm: Now, we write in English the steps that generate the desired behavior. The steps are just an algorithm. Here is the pattern of algorithm we saw a bit earlier:

1. read the input data
2. compute the answer from the data
3. display the answer as output
We can express the steps for change-making in the algorithm pattern:
  1. read the quantities of coins
  2. compute the value of the coins
  3. print the value as dollars and cents
Steps 1-3 show the order in which the program should acquire data, compute, and print, but many details are missing --- what we have written so far is like an outline of an essay for English class. We now refine the algorithm by adding details to the outline that make the algorithm look more and more like a Python program:
  1. read the quantities of coins:
    quarters = read "How many quarters? "
    dimes = read "How many dimes? "
    nickels = read "How many nickels? "
    pennies = read "How many pennies? "
    
  2. compute the value:
    total = quarters * 25  +   dimes * 10  +   nickels * 5  +  pennies * 1
    dollars = total / 100   # remember that int division forgets the fraction !
    cents = total % 100  # remember that int modulo keeps the remainder !
    
  3. print the value:
    print "The total is", dollars, "and", cents
    
The refinement steps let us ``ease into'' the hard work of explaining completely and precisely what the computer must do, in the language of Python. In the example, Step 2 was a bit tricky, but since we studied integer division and modulo, we made good use of our knowledge.

Stage 3. write and test: Now we make the refined algorithm into a Python program --- There should be enough details listed that we need not think too hard at this point! Here is what we have:

=======================

# Total
#   computes the dollars-cents value of a collection of U.S. coins.

quarters = int(raw_input("How many quarters? "))
dimes = int(raw_input("How many dimes? "))
nickels = int(raw_input("How many nickels? "))
pennies = int(raw_input("How many pennies? "))

total = (quarters * 25) + (dimes * 10) + (nickels * 5) + (pennies * 1)
dollars = total / 100   # integer division forgets the fraction
cents = total % 100  # modulo keeps the remainder

print "The total is", dollars, "and", cents

raw_input("\n\nHave a nice day.")

==============================
You should test the program with the behaviors you wrote in Stage 1 as well as with a variety of reasonable and silly input values. (For example, what happens if your program receives -24 nickels ? Or, 3.6 quarters ? Are you happy with the program's outputs for these cases, or do you wish to make some assumptions about the inputs that are reasonable ?)

Don't forget to write an execution trace or two, if you do not understand the behaviors you see produced by the computer for your program!

Stage 4. document: Finally, write the commentary that appears in every program: List the program's name, its purpose, input assumptions, and guarantees of correct output. For the change program, we might write this:

# Total
#   computes the dollars-cents value of a collection of U.S. coins.
# assumed inputs:
#   the quantity of quarter coins, a nonnegative int
#   the quantity of dime coins, a nonnegative int
#   the quantity of nickel coins, a nonnegative int
#   the quantity of pennies, a nonnegative int
# guaranteed output: the total value of the coins, stated in dollars and cents
The documentation makes clear that the input numbers should be nonnegative integers (because it would be ridiculous to compute the monetary value of some ``negative'' quantity of coins). The demands on the inputs generate assertions that we can add to the program. We should also perform the necessary algebra to prove that the guaranteed output will be as expected.

Here is the complete, documented, analyzed program:

FIGURE===============================================

# Total
#   computes the dollars-cents value of a collection of U.S. coins.
# assumed inputs:
#   the quantity of quarter coins, a nonnegative int
#   the quantity of dime coins, a nonnegative int
#   the quantity of nickel coins, a nonnegative int
#   the quantity of pennies, a nonnegative int
# guaranteed output: the total value of the coins, stated in dollars and cents

quarters = int(raw_input("How many quarters? "))
dimes = int(raw_input("How many dimes? "))
nickels = int(raw_input("How many nickels? "))
pennies = int(raw_input("How many pennies? "))

assert quarters >= 0  and  dimes >= 0  and  nickels >=0  and  pennies >= 0

total = (quarters * 25) + (dimes * 10) + (nickels * 5) + (pennies * 1)
dollars = total / 100   # integer division forgets the fraction
cents = total % 100  # modulo keeps the remainder
#! assert:  total >= 0  and  total = (dollars * 100) + cents

print "The total is", dollars, "and", cents

raw_input("\n\nHave a nice day.")

ENDFIGURE=================================================

The Python assert command protects the program so that it is not forced to compute on bad inputs. The usual calculations produce this knowledge at the place labelled #!:

quarters >= 0  and  dimes >= 0  and  nickels >=0  and  pennies >= 0
total = (quarters * 25) + (dimes * 10) + (nickels * 5) + (pennies * 1)
dollars = total / 100
cents = total % 100
Applying algebra, we quickly calculate that
total >= 0
and that
total = (dollars * 100) + cents
which verifies that we have printed the correct dollars-and-cents numbers for the input.

If you practice now the steps of program development given here, you will find it easier to design interesting, correctly working programs.


2.9.4 Testing

An important part of programming is testing. Already you have probably discovered that testing will uncover mistakes in the way you typed Python commands as well as mistakes in the way the commands compute on data and print their outputs. Let's look at samples of these.

Syntax errors

These arise when you ``spell'' a Python command incorrectly, such as
printt "the end"
or use punctuation or parentheses incorrectly:
x = (2 + 1))
When the Python interpreter reads such a command, it will reply with an error message, and often the message is a bit difficult to understand. Here is an example, shown to you as a warning:
hours = int( raw_input("Type hours, an int: ")
minutes = hours * 60
(Notice the missing right bracket in the first line.) When this script is executed, there is a surprising reply:
$ python Error.py
  File "Error.py", line 2
    minutes = hours * 60
          ^
SyntaxError: invalid syntax
Of course, there is nothing wrong with line 2 --- it's line 1 that hasn't ended properly ! So, don't hesitate to look at the lines just before an error message as well as the line that is supposedly erroneous.

Execution errors

These arise when we compute an answer incorrectly. Here is an example. Perhaps we enter these commands:
hours = int( raw_input("Type hours, an int: "))
minutes = hour * 60
and when we test the script, we see this:
$ python Error.py
Type hours, an int: 4
Traceback (most recent call last):
  File "Error.py", line 3, in ?
    minutes = hour * 60
NameError: name 'hour' is not defined
The interpreter notices that we have mistakenly used hour instead of hours on line 3.

But other errors cannot be noticed by the Python interpreter. Again, we are converting hours to minutes and type

minutes = hours + 60
there is no way that the Python interpreter can identify the incorrect use of +. This is why we must write multiple scenarios and test the program with the scenarios.

Use a command window to test your program!

It is easy to start a Python program --- double-click on its icon. But if the program contains an error, then the error message will flash onto the display and disappear almost immediately!

It is better to test a new Python program by starting it within a command window:

  1. Start a command-prompt window.
  2. cd to the folder where your program lives.
  3. Start your program in the command-prompt window, e.g., if your program is named P.py, type python P.py.

This starts your program and makes the program show its work in the opened command-prompt window. If there is an error, the error message will appear in the window.


2.10 Summary of Python

Here is a summary of what we have learned so far:

A Python PROGRAM is a sequence of COMMANDs, one per line. The COMMANDs are executed one after the other.

A COMMAND can be

There are many possible forms of EXPRESSION:

A Python program has a meaning (semantics): When a program is started, it is copied into computer storage, along with the Python interpreter and an empty namespace. The Python interpreter reads the program's commands, one by one, and tells the CPU what to do to compute the commands. The program's variables are constructed in the namespace.

A program should be designed, written, and tested in stages:

  1. describe the program's intended behavior
  2. design the program's algorithm
  3. write the program based on the algorithm and test it
  4. document your work with assume-guarantee conditions and assertions


2.10.1 Constructing a Shortcut

Once you have written a Python program that you like, perhaps you wish to make a icon for it on your desktop, so that you can start the program by double clicking on the icon --- this is called a shortcut. This is easy to do with Windows XP.

Say that you want a shortcut for a program, Pgm.py, which is saved in the folder, C:\MyPython:

Now, you can start Pgm.py by double clicking on the shortcut.

The shortcut icon is actually these commands, which execute when you double click on the icon:

set path=C:\Python22
cd C:\MyPython
python Pgm.py
You can read the program and edit it by right-clicking on the icon, selecting OpenWith and selecting Notepad.