Learning Objectives
- Read and write programs using the Python IF and IF/ELIF/ELSE statements to implement a simple decision structures.
- Write simple exception handling code to catch simple Python run-time errors.
- Read and write programs using the Python FOR and WHILE statements to implement a simple loop structures.
- Construct and implement algorithms that use decision and loop structures.
- Apply basic file processing concepts and techniques for reading and writing text files in Python.
Boolean Expressions
Arithmetic expressions evaluate to numeric values; a Boolean expression may have only one of two possible values: false or true. While on the surface Boolean expressions may appear very limited compared to numeric expressions, they are essential for building more interesting and useful programs.
The simplest Boolean expressions in Python are True
and False
. In the Python interactive shell we see:
>>> True
True
>>> False
False
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>
We see that bool
is the name of the class representing Python’s Boolean expressions. The following code (booleanVars.py)
is a simple program that shows how Boolean variables can be used.
# Assign some Boolean variables
a = True
b = False
print('a =', a, ' b =', b)
# Reassign a
a = False
print('a =', a, ' b =', b)
The results of running this program are shown below:
a = True b = False
a = False b = False
>>>
A Boolean variable is also a Boolean expression as we saw in Unit 2. An expression comparing numeric expressions for equality or inequality is also a Boolean expression. The simplest kinds of Boolean expressions use relational operators (or comparison operators) to compare two expressions. Table 6 lists the relational operators available in Python.
Expression |
Meaning |
|
True if x equals y (mathematical equality, not assignment); otherwise, false |
|
True if x less than y; otherwise, false |
|
True if x less than and equal to y; otherwise, false |
|
True if x greater than y; otherwise, false |
|
True if x greater than and equal to y; otherwise, false |
|
True if x not equal to y; otherwise, false |
Table 6: Python Relationa/Comparisonl Operators
In the Python interactive shell we see some examples of Boolean expressions:
>>> 10 < 20
True
>>> 10 >= 20
False
>>> x = 19
>>> y = 29
>>> x < 100
True>>> x != y
True
An expression like 10 < 20
is legal but of little use, since 10 < 20
is always true; the expression True
is equivalent, simpler, and less likely to confuse human readers. Since variables can change their values during a program’s execution (and often do!), Boolean expressions are most useful when their truth values depend on the values of one or more variables.
The relational/comparison operators are binary operators and are all left associative. They all have a lower precedence than any of the arithmetic operators; therefore, Python evaluates the expression
x + 2 < y / 10
as if parentheses were placed as so:
(x + 2) < (y / 10)
Logical operators
There are three logical operators: and
, or
, and not
. The semantics (meaning) of these operators is similar to their meaning in English. For example, x > 0
and x < 10
is true only if x
is greater than 0 and less than 10.
n%2 == 0 or n%3 == 0
is true if either or both of the conditions is true, that is, if the number is divisible by 2 or 3.
Finally, the not
operator negates a Boolean expression, so not (x > y)
is true if x > y
is false, that is, if x
is less than or equal to y
.
Strictly speaking, the operands of the logical operators should be Boolean expressions, but Python is not very strict. Any nonzero number is interpreted as True
:
>>> 42 and True
True
This flexibility can be useful, but there are some subtleties to it that might be confusing. You might want to avoid it (unless you know what you are doing).
Conditional execution
In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Conditional statements give us this ability. The simplest form is the if
statement:
if x > 0:
print('x is positive')
The Boolean expression after if
is called the condition. If it is true, the indented statement runs. If not, nothing happens. See the corresponding flowchart in figure 42.
if
statements have the same structure as function definitions: a header followed by an indented body. Statements like this are called compound statements.
There is no limit on the number of statements that can appear in the body, but there has to be at least one.
A second form of the if statement is “alternative execution” (if-else
), in which there are two possibilities and the condition determines which one runs. The syntax looks like this:
if x % 2 == 0:
print('x is even')
else:
print('x is odd')
Modulus or remainder operator, ‘%
’, returns the remainder of two numbers. So in this example, if the remainder when x
is divided by 2 is 0, then we know that x
is even, and the program displays an appropriate message. If the condition is false, the second set of statements runs. Since the condition must be true or false, exactly one of the alternatives will run. The alternatives are called branches, because they are branches in the flow of execution. See the corresponding flowchart in figure 42.
The if
statement is used to check a condition: if the condition is true, we run a block of statements (called the if-block), else we process another block of statements (called the else-block). The else clause is optional. In our earlier examples we only had one statement in a block. Sometimes there are more than two possibilities and we need more than two branches. One way to express a computation like that is a chained conditional (if-elif-else
). The following program, ifElse.py
, shows us multiple statements in each block.
number = 23
guess = int(input('Enter an integer : '))
if guess == number:
# New block starts here
print('Congratulations, you guessed it.')
print('(but you do not win any prizes!)')
# New block ends here
elif guess < number:
# Another block
print('No, it is a little higher than that')
# You can do whatever you want in a block ...
else:
print('No, it is a little lower than that')
# you must have guessed > number to reach here
print('Done')
# This last statement is always executed,
# after the if statement is executed.
In this program, we take guesses from the user and check if it is the number that we have. We set the variable number
to any integer we want, say 23. Then, we take the user’s guess using the input()
function. We then convert this string to an integer using int
and then store it in the variable guess
.
Next, we compare the guess of the user with the number we have chosen. If they are equal, we print a success message. Notice that we use indentation levels to tell Python which statements belong to which block. Then, we check if the guess is less than the number, and if so, we inform the user that they must guess a little higher than that.
After Python has finished executing the complete if
statement along with the associated elif
and else
clauses, it moves on to the next statement in the block containing the if
statement. In this case, it is the main block (where execution of the program starts), and the next statement is the print('Done')
statement. After this, Python sees the end of the program and simply finishes up.
The following code is another example of a conditional statement with more than two branches:
if x < y:
print('x is less than y')
elif x > y:
print('x is greater than y')
else:
print('x and y are equal')
elif
is an abbreviation of “else if”. Again, exactly one branch will run. There is no limit on the number of elif
statements. See the corresponding flowchart in figure 43. If there is an else
clause, it has to be at the end, but there doesn’t have to be one. See the following example:
if choice == 'a':
draw_a()
elif choice == 'b':
draw_b()
elif choice == 'c':
draw_c()
Each condition is checked in order. If the first is false, the next is checked, and so on. If one of them is true, the corresponding branch runs and the statement ends. Even if more than one condition is true, only the first true
branch runs. It is good practice to include the else
clause as the final branch in the if-elif-else
statement.
Practice – Write a program to accept a test score as input and print out the corresponding letter grade. First examine the flowchart (figure 44) of the problem we are solving. Then, using the Python editor, enter the following code (save as testGrade.py
):
#accept a test score as input and print out the corresponding letter grade
testScore = float(input("Enter a test score from 0 to 100: "))
# conditional statement to determine and print the test letter grade
if testScore >= 90:
print("your grade is A")
elif testScore >= 80:
print("your grade is B")
elif testScore >= 70:
print("your grade is C")
elif testScore >= 60:
print("your grade is D")
else:
print("your grade is F")
Output:
Let us examine how this program works.
Python Statement |
Explanation |
|
Accept a numeric test grade from the user as a string and convert the number to a floating point values. Save this value in a variable named |
|
The first branch of this chained conditional is executed. If this condition (the test score is greater than or equal to 90) is |
|
The second branch of this chained conditional is executed. If this condition (the test score is greater than or equal to 80) is |
|
The third branch of this chained conditional is executed. If this condition (the test score is greater than or equal to 70) is |
|
The fourth branch of this chained conditional is executed. If this condition (the test score is greater than or equal to 60) is |
|
The “ |
One conditional can also be nested within another called nested conditionals. Earlier in this section we saw the following example using a chained conditional (if-elif-else
).
if x < y:
print('x is less than y')
elif x > y:
print('x is greater than y')
else:
print('x and y are equal')
We could have just as easily written this code using nested conditionals like this:
if x == y:
print('x and y are equal')
else:
if x < y:
print('x is less than y')
else:
print('x is greater than y')
The outer conditional contains two branches. The first branch contains a simple statement. The second branch contains another if statement, which has two branches of its own. Those two branches are both simple statements, although they could have been conditional statements as well.
Although the indentation of the statements makes the structure apparent, nested conditionals become difficult to read very quickly. It is a good idea to avoid them when you can.
Logical operators often provide a way to simplify nested conditional statements. For example, we can rewrite the following code using a single conditional:
if 0 < x:
if x < 10:
print('x is a positive single-digit number.')
The print statement runs only if we make it past both conditionals, so we can get the same effect with the and operator:
if 0 < x and x < 10:
print('x is a positive single-digit number.')
For this kind of condition, Python provides even a more concise option:
if 0 < x < 10:
print('x is a positive single-digit number.')
Exception Handling
In our programming experience so far we have encountered several kinds of programming run-time exceptions, such as division by zero, attempting to read a variable that has not been defined, and attempting to convert a non-number to an integer. We have seen these and other run-time exceptions immediately terminate a running program.
Exceptions are a means of breaking out of the normal flow of control of a code block in order to handle errors or other exceptional conditions. An exception is raised at the point where the error is detected; it may be handled by the surrounding code block or by any code block that directly or indirectly invoked the code block where the error occurred. The Python interpreter raises an exception when it detects a run-time error (such as division by zero).
Python provides a standard mechanism called exception handling that allows programmers to deal with these kinds of run-time exceptions and many more. Rather than always terminating the program’s execution (this is called a program “crash”), an executing program can detect the problem when it arises and possibly execute code to correct the issue it in some way.
Exceptions occur when exceptional situations occur in your program. Similarly, what if your program had some invalid statements? This is handled by Python which raises its hands and tells you there is an error.
Errors
Consider the simple print
function call. What if we misspell print
as Print
? Note the capitalization. In this case, Python raises a syntax error. The following output appears in the Python shell. Observe that a NameError
is raised and also the location of the error detected is printed. This is what an error handler for this error does.
>>>Print("hello there!")
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
Print("hello there!")
NameError: name 'Print' is not defined
>>> print("hello there!")
hello there!
>>>
Exceptions
Let us try to read input from the user. In the Python shell we enter the first line below and hit the Enter key. When the computer prompts for input, instead press [ctrl-c] (this example is with Windows) and see what happens.
>>>
>>> text = input("Enter something: ")
Enter something:
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
text = input("Enter something: ")
KeyboardInterrupt
>>>
Python raises an error called KeyboardInterrupt
which basically means it was interrupted when it expected to get user input.
Let us look at another example. Here we will read input from the user and then attempt to convert the string input into an integer.
>>> num = input("Enter a number between 1 and 10: ")
Enter a number between 1 and 10: no
>>> int(num)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
int(num)
ValueError: invalid literal for int() with base 10: 'no'
>>>
Python raises an error called ValueError
which is letting us know that the string ’no’
cannot be converted to an integer value. Programmers can avoid this scenario by checking that a string’s value can be converted to a number value.
Another common exception occurs when we try to evaluate a comparison which does not make sense. Consider the following Python conditional statements executed in the Shell window:
>>> 12 > 5
True
>>> 12 == 5
False
>>> 12 < 'a'
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
12 < 'a'
TypeError: '<' not supported between instances of 'int' and 'str'
>>>
Python raises an error called TypeError
which is letting us know that the condition 12 < 'a'
cannot be performed.
Handling Exceptions
Essentially, exceptions are events that modify program’s flow, either intentionally or due to errors. They are special events that can occur due to an error, e.g. trying to divide a number by zero. Exceptions, by definition, don’t occur very often; hence, they are the “exception to the rule”.
Exceptions are everywhere in Python. Virtually every module in the standard Python library uses them, and Python itself will raise them in a lot of different circumstances. One use of exceptions is to catch an error and allow the program to continue working instead of crashing ungracefully.
This is the most common way to use exceptions. When programming with the Python command line interpreter (in the Shell window), you don’t need to worry about catching exceptions. Your program is usually short enough to not be hurt too much if an exception occurs. Plus, having the exception occur at the command line is a quick and easy way to tell if your code logic has a problem. However, if the same error occurred in your saved .py file program, it will crash (fail) and stop working.
Exceptions can be thought of as a special form of the if-else
statements. You can realistically do the same thing with if
blocks as you can with exceptions. However, as already mentioned, exceptions aren’t processed until they occur; if
blocks are processed all the time. Proper use of exceptions can help the performance of your program. The more infrequent the error might occur, the better off you are to use exceptions; using if
blocks requires Python to always test extra conditions before continuing. Exceptions also make code management easier: if your programming logic is mixed in with error-handling if
statements, it can be difficult to read, modify, and debug your program.
We can handle exceptions using the try-except-else
statement. Briefly, try
creates a block that attempts to perform an action. If that action fails, the except
block catches any exception that is raised and notifies the user that an error occurred, then stops executing the program. If the code within the try block does not produce an exception, the program’s execution continues with code in the else
block.
Practice – Here is a simple program that uses exception processing. It simply produces the quotient of 2 numbers. Try entering, saving and running the following program (exceptionHandling.py
).
# exception handling
first_number = input ( "Enter the first number: ") #gets input from keyboard
sec_number = input ( "Enter the second number: " )
try :
num1 = float( first_number ) #try turning keyboard input into floats
num2 = float( sec_number )
result = num1/num2 #try dividing num1 by num2
except:
print("Error: enter numbers only; num2 cannot equal zero")
else :
print(str(num1) + "/" + str(num2) + "=" + str(result))
The output from executing this program, three separate times, is shown below.
RESTART: C:/Users/lh166266.UALBANY/Dropbox/OER Textbook/TEXTBOOK OER/Code/exceptionHandling.py
Enter the first number: 33
Enter the second number: 22
33.0/22.0=1.5
>>>
RESTART: C:/Users/lh166266.UALBANY/Dropbox/OER Textbook/TEXTBOOK OER/Code/exceptionHandling.py
Enter the first number: 33
Enter the second number: twenty
Error: enter numbers only; num2 cannot equal zero
>>>
RESTART: C:/Users/lh166266.UALBANY/Dropbox/OER Textbook/TEXTBOOK OER/Code/exceptionHandling.py
Enter the first number: 33
Enter the second number: 0
Error: enter numbers only; num2 cannot equal zero
>>>
In this example we simply print out a message to the user in the except block and then gracefully terminate our program. We use the else
statement at the end to perform the rest of the program logic if all goes well. As stated before, the whole try block could also have been written as if/else
statements but that would have required Python to process each statement to see if they matched. By using exceptions, the “default” case is assumed to be true until an exception actually occurs. This speeds up processing.
It’s better to include error-checking, such as exceptions, in your code as you program rather than as an afterthought. A special “category” of programming involves writing test cases (we wrote test cases for our algorithms in Unit 1!) to ensure that most possible errors are accounted for in the code, especially as the code changes or new versions are created. Recall the test cases we were introduced to when writing our algorithms in Unit 1. By planning ahead and putting exception handling into your program at the outset, you ensure that problems are caught before they can cause problems.
Exceptions are a means of breaking out of the normal flow of control of a code block in order to handle errors or other exceptional conditions. An exception is raised at the point where the error is detected; it may be handled by the surrounding code block or by any code block that directly or indirectly invoked the code block where the error occurred. The Python interpreter raises an exception when it detects a run-time error (such as division by zero).
Practice with Handling Exceptions in our Programs
Let us review some examples of handling exceptions in some of our programs we have written.
Practice #1 – Calculating the distance between two points:
# calculates the distance between two points
import math
print("This program calculates the distance between two points.")
print() #print a blank line
x1 = float(input("Enter the x for the first point: "))
y1 = float(input("Enter the y for the first point: "))
print()
x2 = float(input("Enter the x for the second point: "))
y2 = float(input("Enter the y for the second point: "))
distance = math.sqrt((x2-x1)**2 + (y2-y1)**2)
print()
print("The distance between the points is", distance)
The output when executing this program with non-numeric input is seen below:
>>>
RESTART:
C:/Users/lh166266.UALBANY/distanceBetweenPointsExceptionHandling.py
This program calculates the distance between two points.
Enter the x for the first point: 17
Enter the y for the first point: 23
Enter the x for the second point: 88
Enter the y for the second point: 9p
Traceback (most recent call last):
File "C:\Users\lh166266.UALBANY\distanceBetweenPoints.py", line 12, in <module>
y2 = float(input("Enter the y for the second point: "))
ValueError: could not convert string to float: '9p'
>>>
Rewrite this program to include exception handling to catch the ValueError
when we try and convert our user input into floating point numbers.
# Calculates the distance between two points
import math
print("This program calculates the distance between two points.")
print()
try:
x1 = float(input("Enter the x for the first point: "))
y1 = float(input("Enter the y for the first point: "))
print()
x2 = float(input("Enter the x for the second point: "))
y2 = float(input("Enter the y for the second point: "))
except:
print("Error: enter numeric values only")
else:
distance = math.sqrt((x2-x1)**2 + (y2-y1)**2)
print()
print("The distance between the points is", distance)
The output when executing the revised program with non-numeric input is far more user friendly!
>>>
RESTART:
C:/Users/lh166266.UALBANY/distanceBetweenPointsExceptionHandling.py
This program calculates the distance between two points.
Enter the x for the first point: 17
Enter the y for the first point: 23
Enter the x for the second point: 88
Enter the y for the second point:9p
Error: enter numeric values only
>>>
Practice #2 – Guess the Number:
number = 23
guess = int(input('Enter an integer : '))
if guess == number:
print('Congratulations, you guessed it.')
print('(but you do not win any prizes!)')
elif guess < number:
print('No, it is a little higher than that')
else:
print('No, it is a little lower than that')
print('Done')
The output when executing this program with non-numeric input is seen below:
>>>
RESTART: C:/Users/lh166266.UALBANY/ifElse.py
Enter an integer : 8g6
Traceback (most recent call last):
File "C:\Users\lh166266.UALBANY\Dropbox\OER Textbook\TEXTBOOK OER\Code\ifElse.py", line 2, in <module>
guess = int(input('Enter an integer : '))
ValueError: invalid literal for int() with base 10: '8g6'
</span style="color: #ff0000;">>>>
Rewrite this program to include exception handling to catch the ValueError
when we try and convert the user input into an integer.
# Guess my number
number = 23 . #this is ‘my number’
try:
guess = int(input('Enter an integer : '))
except:
print("ERROR: enter whole numbers only")
else:
if guess == number:
print('Congratulations, you guessed it.')
print('(but you do not win any prizes!)')
elif guess < number:
print('No, it is a little higher than that')
else:
print('No, it is a little lower than that')
print('Done')
The output when executing the revised program with non-numeric input gracefully ends rather than crashing!
>>>
RESTART: C:/Users/lh166266.UALBANY/ifElseExceptionHandling.py
Enter an integer : 88m
ERROR: enter whole numbers only
>>>
Iteration
This section is about iteration, which is the ability to run a block of statements repeatedly. Computers are often used to automate repetitive tasks. Repeating identical or similar tasks without making errors is something that computers do well and people do poorly. In a computer program, repetition is also called iteration.
The while Statement
A while
statement is an iterative control statement that repeatedly executes a set of statements based on a provided Boolean expression (condition). All iterative control needed in a program can be achieved by use of the while
statement, though, as we will see later, other iterative control statements can be more useful for solving some computational problems.
Here is a version of a countdown function that uses a while statement:
def countdown(n):
while n > 0:
print(n)
n = n - 1
print('Blastoff!')
You can almost read the while
statement as if it were English. It means, “While n is greater than 0, display the value of n and then decrement n. When you get to 0, display the word Blastoff!”
Here is the flow of execution for a while statement:
- Determine whether the condition is true or false.
- If false, exit the while statement and continue execution at the next statement.
- If the condition is true, run the body and then go back to step 1.
This type of flow is called a loop because the third step loops back around to the top.
The body of the loop should change the value of one or more variables so that the condition becomes false eventually and the loop terminates. Otherwise the loop will repeat forever, which is called an infinite loop.
In the case of the countdown function, we can prove that the loop terminates: if n is zero or negative, the loop never runs. Otherwise, n gets smaller each time through the loop, so eventually we have to get to 0.
Practice 1: Try executing the following program which uses the countdown function (countdown.py
).
def countdown(n):
while n > 0:
print(n)
n = n - 1
print('Blastoff!')
num = input("enter a positive number to countdown from: ")
try:
num=int(num)
except:
print("ERROR: enter a whole number")
else:
countdown(num)
An example of the output after execution:
RESTART: C:/Users/lh166266.UALBANY/Code/countdown.py
enter a number to countdown from: 9
9
8
7
6
5
4
3
2
1
style="color: #003366;">Blastoff!
>>
>The variable n
in the countdown.py
program is referred to as a counter. A counter variable is used to count something, usually initialized to zero and then incremented (or decremented) and is commonly used in programs.
The while
statement allows you to repeatedly execute a block of statements as long as a condition is true. A while
statement is an example of what is called a looping statement. A while
statement can have an optional else clause. Let us look at the following program (while.py
)
number = 23
running = True
while running:
guess = int(input('Enter an integer : '))
if guess == number:
print('Congratulations, you guessed it.')
# this causes the while loop to stop
running = False
elif guess < number:
print('No, it is a little higher than that.')
else:
print('No, it is a little lower than that.')
else:
print('The while loop is over.')
# Do anything else you want to do here
print('Done')
In this program, we are still playing the guessing game, but the advantage is that the user is allowed to keep guessing until he guesses correctly – there is no need to repeatedly run the program for each guess, as we have done in the previous section. This aptly demonstrates the use of the while
statement.Let us examine more closely the code in this program (while.py
).
Python Statement |
Explanation |
|
We set the variable number to a number we want; here we choose the number ‘23’.The variable running is referred to as a ‘flag’ variable. Flag variables go by many different names, but they all represent a variable (usually of |
|
This where the loop starts. First, we check if the variable |
|
This is the ‘body’ of the entire loop. The user is asked to enter an integer number which is converted into an integer and saved in the variable Next, we compare the guess of the user with the number we have chosen. If they are equal, we print a success message and set our flag variable, Then, we check if the guess is less than the number, and if so, we inform the user that they must guess a little higher than that. Finally we check if the guess is greater than the number, and if so, we inform the user that they must guess a little lower than that. |
|
Once we have exited the while loop we print this single statement to indicate to the user that the guessing game is over. |
The following is a sample of output after running this program:
Enter an integer : 5
No, it is a little higher than that.
Enter an integer : 19
No, it is a little higher than that.
Enter an integer:25
No, it is a little lower than that.
Enter an integer:24
No, it is a little lower than that.
Enter an integer: 23
Congratulations, you guessed it.
The while loop is over. Done
>>>
This is an example of an interactive loop because it allows the user to repeat something (in this example the user is guessing a number) on demand.
Practice 2: The following program allows a user to enter any number of nonnegative integers. When the user enters a negative value, the program no longer accepts input, and it displays the sum of all the nonnegative values. If a negative number is the first entry, the sum is zero. This is also an example of interactive loop. [addNonNegatives.py
]
# Allow the user to enter a sequence of nonnegative integers to sum.
entry = 0
# Ensure the loop is entered
sum = 0
# Initialize sum
print("Enter positive numbers to sum (entering a negative number ends the program).")
while entry >= 0:
# A negative number exits the loop
entry = int(input("number: ")) # Get the value
if entry >= 0:
# Is number nonnegative?
sum = sum entry
print("Sum =", sum)
# Display the sum
RESTART:C:/Users/lh166266.UALBANY/Code/addNonNegatives.py
Enter positive numbers to sum (entering a negative number ends the program).
number: 8
number: 9
number: 1
number: 2
number: -9
Sum = 20
Figure 46: Sample Output from addNonNegatives.py
Let us examine more closely the code in this program.
Python Statement |
Explanation |
|
In the beginning we initialize |
|
The variable |
|
This statement provides instructions for this app. |
|
Within the loop we repeatedly add the user’s input values to |
|
Once we have exited the |
Practice 3: Now let us rewrite this program to add additional functionality. In addition to finding the sum of nonnegative values we will calculate the average. [avgNonNegatives.py
]
# Allow the user to enter a sequence of nonnegative integers to sum and find the average.
entry = 0
# Ensure the loop is entered
sum = 0
# Initialize sum
count = 0
# Initialize count
print("Enter positive numbers to sum (entering a negative number ends the program).")
while entry >= 0:
# A negative number exits the loop
entry = int(input("number: "))
# Get the value
if entry >= 0:
# Is number nonnegative?
sum = sum + entry
# Only add it if it is nonnegative
count = count + 1
#increment the count of numbers entered
print("Sum =", sum) # Display the sum
average = sum / count
print("Average =", average)
The program needs not only an accumulator variable (i.e. sum
) but a counter variable also (named count
) to keep track of how many numbers have been entered. We can then calculate the average by dividing the sum by the count.
RESTART: C:/Users/lh166266.UALBANY/Code/avgNonNegatives.py
Enter positive numbers to sum (entering a negative number ends the program).
number:
12
number:
55
number:
31
number:
-11
Sum = 98
Average = 32.666666666666664
Figure 48: Sample Output from avgNonNegatives.py
The break Statement
Sometimes you don’t know it’s time to end a loop until you get half way through the body. In that case you can use the break
statement to jump out of the loop.
For example, suppose you want to take input from the user until they type done
. You could write:
while True:
line = input('> ')
if line == 'done':
break
print(line)print('Done!')
The loop condition is True
, which is always true, so the loop runs until it hits the break
statement.
Each time through, it prompts the user with an angle bracket. If the user types done, the break
statement exits the loop. Otherwise the program echoes whatever the user types and goes back to the top of the loop. Here’s a sample run:
> hello
hello
> done
Done!
This way of writing while
loops is common because you can check the condition anywhere in the loop (not just at the top) and you can express the stop condition affirmatively (“stop when this happens”) rather than negatively (“keep going until that happens”).
Note that the break
statement works with the for loop as well.
The continue Statement
The continue
statement is used to tell Python to skip the rest of the statements in the current loop block and to continue to the next iteration of the loop.
Let us examine the following example (save as continue.py
):
# user is to enter a string of at minimum 3 words
# to end the user is to enter the word 'quit'
while True:
data = input('Enter at least 3 words: ')
if data == 'quit':
break
if len(data) < 3:
print('Too small')
continue
print('Input (data) is of sufficient length')
# Do other kinds of processing here...
Sample Output:
>>>
RESTART:C:/Users/lh166266.UALBANY/Code/continue.py
Enter at least 3 words:
hi
Too small
Enter at least 3 words:
how are you
Input (data) is of sufficient length
Enter at least 3 words:
quit
>>>
In this program, we accept input from the user, but we process the input string only if it is at least 3 words long or the user enters the word ‘quit’. So, we use the built-in len
function to get the length and if the length is less than 3, we skip the rest of the statements in the block by using the continue
statement. Otherwise, the rest of the statements in the loop are executed, doing any kind of processing we want to do here. When the user enters the word ‘quit’
we exit the loop using the break
statement, then end the program. This is an example of an input validation loop. In an input validation loop (commonly designed using the while
loop) the program inspects user input before it is processed by the program and if input is invalid it prompts user to enter correct data.
Note that the continue
statement works with the for
loop as well.
The for…in Statement
The for..in
statement is another looping statement which iterates over a sequence of objects i.e. go through each item in a sequence. Recall that a sequence is just an ordered collection of items. Let us look at the following program, for.py
.
for i in range(1, 5):
print(i)
else:
print('The for loop is over')
This is what the output of the program looks like in the Python shell after it runs:
1
2
3
4
The for loop is over
>>>
In this program, we are printing a sequence of numbers. We generate this sequence of numbers using the built-in range
function.
What we do here is supply it two numbers and range
returns a sequence of numbers starting from the first number and up to the second number. For example, range
(1,5
) gives the sequence [1, 2, 3, 4]
. By default, range
takes a step count of 1
. If we supply a third number to range
, then that becomes the step count. For example, range(1,5,2)
gives [1,3]
. Remember that the range
extends up to the second number i.e. it does not include the second number.
The for
loop then iterates over this range – for i in range(1,5)
is equivalent to for i in [1, 2, 3, 4]
which is like assigning each number (or object) in the sequence to i
, one at a time, and then executing the block of statements for each value of i
. In this case, we just print the value in the block of statements.
The general form of the range
expression is range( begin,end,step )
where
begin
is the first value in the range; if omitted, the default value is 0end
is one past the last value in the range; the end value is always required and may not be omittedstep
is the amount to increment or decrement; if the step parameter is omitted, it defaults to 1 (counts up by ones)
begin
, end
, and step
must all be integer expressions; floating-point expressions and other types are not allowed. The arguments in the range expression may be literal numbers (like 10), variables (like x, if x is equal to an integer), and arbitrarily complex integer expressions.
The range
expression is very flexible. Consider the following loop that counts down from 21 to 3 by threes:
for n in range(21, 0, -3):
print(n, end=' ')
It prints:
21 18 15 12 9 6 3
Thus range(21, 0, -3)
represents the sequence 21;18;15;12;9; 3
.
The expression range(1000)
produces the sequence 0;1;2; : : : ; 999.
The following code computes and prints the sum of all the positive integers less than 100:
sum = 0 # Initialize sum
for i in range(1, 100):
sum += i
print(sum)
Remember that the else
block is optional. When included, it is always executed once after the for loop is over unless a break
statement is encountered.
So far we have used the for
loop to iterate over integer sequences because this is a useful and common task in developing apps. The for
loop, however, can iterate over any iterable object, such as a string.
We can use a for
loop to iterate over the characters that comprise a string. The following program uses a for
loop to print the individual characters of a string (printLetters.py)
.
word = input('Enter a word: ')
for letter in word:
print(letter)
Sample output:
RESTART: C:/Users/lh166266.UALBANY/Code/printLetters.py
Enter a word: hello
h
e
l
l
o
>>>
Practice 1: Write a program to solve the following problem. [printWords.py]
Input: Number of words to be entered; this value must be a positive integer greater than zero.
# Ask the user how many words they want to enter
# then print the words together on one line.
sentence = ""
num = input("How many words do you want to enter? ")
try:
num=int(num)
except:
print ("ERROR: enter a number")
else:
if num > 0: #check for a positive number
for i in range(num):
word = input("enter a word: ")
sentence = sentence + " " + word
print(sentence)
else:
print("Will only accept a positive integer number. Ending program")
Note the error checking performed in the program:
- Ensures the user only enters integer numbers as input
- Ensures the user enters a positive integer
Practice 2: Write a program to solve the following problem. [numWords.py]
Unlike the example where we used a for loop to iterate over the characters of a word, we need to use a string object’s method to break the string into words. When you need to break a large string down into smaller chunks, or strings, you use the split()
string method. By default, split()
takes whitespace as the delimiter. Try executing this program
(numWords.py)
# Ask the user to enter in a complete sentence and display the number of words in the sentence.
sentence = input("please enter an awe inspiring sentence or two: ")
words = sentence.split()
print("you entered", len(words), "words")
print("here are the individual words you entered:", words)
Example output:
please enter an awe inspiring
sentence or two:
When I need to build a web app, I reach for the Python programming language. When I need to automate some small task on my system, I reach for Python. Python rocks!
you entered 32 words
here are the individual words you entered: ['When', 'I', 'need', 'to', 'build', 'a', 'web', 'app,', 'I', 'reach', 'for', 'the', 'Python', 'programming', 'language.', 'When', 'I', 'need', 'to', 'automate', 'some', 'small', 'task', 'on', 'my', 'system,', 'I', 'reach', 'for', 'Python.', 'Python', 'rocks!']
>>>
Once you have used split
to break the string into a list of words, you can use the index operator (square bracket) to look at a particular word in the list.
>>> sentence = "Python is a general purpose programming language named after Monty Python."
>>> words = sentence.split()
>>> print(words)
['Python', 'is', 'a', 'general', 'purpose', 'programming', 'language', 'named', 'after', 'Monty', 'Python.']
>>> print(words[9], words[3], words[6])
Monty general language
>>>
Enhance this program to loop through each word in the list named words and print each word in uppercase on its own line (uppercaseWords.py
.
# Ask the user to enter in a complete sentence and display each work in uppercase.
sentence = input("please enter an awe inspiring sentence or two: ")
words = sentence.split()
print("you entered", len(words), "words")
print("here are the individual words you entered:")for word in words:
print(word.upper())
Example output:
please enter an awe inspiring sentence or two:
Python is a general purpose programming language named after Monty Python.
you entered 11 words
here are the individual words you entered:
PYTHON
IS
A
GENERAL
PURPOSE
PROGRAMMING
LANGUAGE
NAMED
AFTER
MONTYPYTHON.
>>>
How to choose between the for
and while
loop?
Use a for
loop if you know, before you start looping, the maximum number of times that you’ll need to execute the body. For example, if you’re traversing a list of elements, you know that the maximum number of loop iterations you can possibly need is “all the elements in the list”. Or if you need to print the 12 times table, we know right away how many times the loop will need to run.
So any problem like “iterate this weather model for 1000 cycles”, or “search this list of words”, “find all prime numbers up to 10000” suggest that a for
loop is best.
By contrast, if you are required to repeat some computation until some condition is met, and you cannot calculate in advance when (of if) this will happen, as we did in this 3n + 1 problem, you’ll need a while
loop.
We call the first case definite iteration — we know ahead of time some definite bounds for what is needed. The latter case is called indefinite iteration — we’re not sure how many iterations we’ll need — we cannot even establish an upper bound!
Nested Loops
Just like withif
statements, while
and for
blocks can contain arbitrary Python statements, including other loops. A loop can therefore be nested within another loop. To see how nested loops work, consider a program that prints out a multiplication times tables (multiplication.py
).
#multiplcation tables
try:
table = int(input("which multiplication times table do you want to
print? (choose from 1 to 12) “))
x = table
except:
print("ERROR: enter a whole number")
else:
if table > 0 and table < 13:
for y in range(1, 13):
print (x,'*', y,'=', x*y)
else:
print ("ERROR: multiplication tables can be generated from 1 to 12 only")
Let us examine more closely the code in this program.
Python Statement |
Explanation |
|
We use the The |
|
The |
|
This statement provides instructions for this app. |
|
This is the end of the program. This block, which prints and error message, only executes if the user did not enter a number in the correct range of 1 to 12. |
Example output:
RESTART: C:/Users/lh166266.UALBANY/Code/multiplication.py
which multiplication times table do you want to print? (choose from 1 to 12)
5
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
5 * 7 = 35
5 * 8 = 40
5 * 9 = 45
5 * 10 = 50
5 * 11 = 55
5 * 12 = 60
>>>Now let us consider adding to this program to generate all the multiplication times tables from 1 to 12. This is easily done with nested loops.
#multiplcation times tables tables
for x in range(1, 13):
for y in range(1, 13):
print (x,'*', y,'=', x*y)
The output after execution of this 3-lines-of-code program generates 144 lines of output!
1 * 1 = 11 * 2 = 21 * 3 = 31 * 4 = 41 * 5 = 51 * 6 = 61 * 7 = 71 * 8 = 81 * 9 = 91 * 10 = 101 * 11 = 111 * 12 = 122 * 1 = 22 * 2 = 42 * 3 = 62 * 4 = 82 * 5 = 102 * 6 = 122 * 7 = 142 * 8 = 162 * 9 = 182 * 10 = 202 * 11 = 222 * 12 = 24...12 * 1 = 1212 * 2 = 2412 * 3 = 3612 * 4 = 4812 * 5 = 6012 * 6 = 7212 * 7 = 8412 * 8 = 9612 * 9 = 10812 * 10 = 12012 * 11 = 13212 * 12 = 144
Basic File Processing
While a program is running, its data is stored in random access memory (RAM) on the computer it is execution on. RAM is fast and inexpensive, but it is also volatile, which means that when the program ends, or the computer shuts down, the data in RAM disappears. To make data available the next time the computer is turned on and the program is started, it has to be written to a non-volatile storage medium, as a file. By reading and writing files, programs can save information between program runs.
So far, the data we have used in this book have all been either coded right into the program, or have been entered by the user. In real life data reside in files.
For our purposes, we will assume that our data files are text files–that is, files filled with characters. The Python programs that you write are stored as text files as are any HTML webpage files. We can create these files in any of a number of ways. For example, we could use a text editor to type in and save the data. We could also download the data from a website and then save it in a file. Regardless of how the file is created, Python will allow us to manipulate the contents. Note that text files have an End-Of-Line (EOL) character to indicate each line’s termination.
Reading and Writing Text Files
In Python, we must open files before we can use them and close them when we are done with them. As you might expect, once a file is opened it becomes a Python object just like all other data. The following table shows the functions and methods that can be with files.
Function/Method Name |
Use |
Explanation |
open |
|
Open a file called workfile.txt and use it for reading. This will return a reference to a file object assigned to the variable |
open |
|
Open a file called workfile.txt and use it for writing. This will also return a reference to a file object assigned to the variable |
close |
|
When a file use is complete, the file must be closed. This will free up any system resources taken up by the open file. |
read |
|
Read the entire contents of the file |
write |
|
Write the contents of string to the file |
readline |
|
Read a single line from the file |
Table 7: File Functions and Methods
Python file object attributes provide information about the file and file state. The following table shows how to identify some of the object’s attributes.
Attribute |
Use |
Explanation |
file.closed |
|
Returns true if |
file.mode |
|
Returns access mode with which |
file.name |
|
Returns name of |
Table 8: File Object Attributes
The statement
file1 = open('myfile.txt', 'r')
creates and returns a file object in the variable named file1
. The first argument to open is the name of the file, and the second argument is a mode (in this example the mode is to read the file). This statement will attempt to read the content of the text file named myfile.txt
. If the file does not exist or the user of the program does not have adequate permissions to open the file, the open
function will raise an exception.
try:
file1 = open('myfile.txt', 'r')
except:
print(“ERROR: unable to open or locate the file”)
# Do other kinds of processing here...
Similar to handling an error of invalid user input we need to use the try-except-else
block to handle trying to read from a file which does not exist The following is an example:
The statement
file2 = open('myfile.txt', 'w')
creates and returns a file object in the variable named file2
which will write data to the text file named myfile.txt
. If the file does not exist, the function creates the file on disk; no exceptions are raised when writing to a file. If a file by that name currently exists, new data will replace the current data stored in the file. This means any pre-existing data in the file will be lost.
Once you have a file object capable of writing (opened with ‘w’) you can save data to the file associated with that file object using the write method. For a file object named file2
, the statement
file2.write('data')
stores the string ‘data’ to the file. The three statements
file2.write('data')
file2.write('compute')
file2.write('process')
writes the text 'datacomputeprocess'
to the file. If our intention is to retrieve the three separate original strings, we must add delimiters to separate the pieces of data. Newline characters serve as good delimiters:
file2.write('data\n')
file2.write('compute\n')
file2.write('process\n')
This places each word on its own line in the text file. The advantage of storing each piece of data on its own line of text is that it makes it easier to read the data from the file with a for
statement. If file2
is a file object created for reading, the following code:
for line in file2:
print(line.strip())
reads in each line of text from the file and prints it out. The variable line
is a string, and we use the strip
method to remove the trailing newline ('\n'
) character.
We also can read the contents of the entire file into a single string using the file object’s read method:
contents = file2.read()
Given the text file from above, the code
in = open('compterms.txt', 'r')
str = in.read()
assigns to str
the string 'data\ncompute\nprocess\n'
.
The open
method opens a file for reading or writing, and the read
, write
, and other such methods enable the program to interact with the file. When the executing program is finished with its file processing it must call the close
method to close the file properly. Failure to close a file can have serious consequences when writing to a file, as data meant to be saved could be lost. Every call to the open function should have a corresponding call to the file object’s close
method.
Practice – Following are two simple programs designed to write data to a file and then read and print each line of a file. Try entering, saving and running the following programs (writeFile.py
and readFile.py
).
file1 = open("compterms.txt", 'w') #Create a file to write to
# write data to the opened file
file1.write('data\n')
file1.write('compute\n')
file1.write('process\n')
file1.write('file format\n')
file1.write('gigabyte\n')
file1.close() # Close the file after processing data
Figure 49: writeFile.py
Figure 50: readFile.py
file1 = open('compterms.txt','r') # try to find & open the file
except:
print('ERROR: unable to open or locate the file')
else:
for line in file1: # Read each line as text
print(line.strip()) # Remove trailing newline character and print the line
file1.close() # Close the file after processing data
This is the output after running this program:
data
compute
process
file format
gigabyte
>>>
We can also read and process each line of data in a file by using the readline()
method. Try entering, saving and running the following programs (readFile2.py)
. The output is the same.
try:
file1 = open('compterms.txt','r') # try to find & open the file
except:
print('ERROR: unable to open or locate the file')
else:
line = file1.readline() # Read the first line
while line: # Enter the loop as long as there is a line of
data to read
print(line.strip()) # Remove trailing newline character and print the line
line = file1.readline() # Read the next line
file1.close() # Close the file after processing data
Processing “Big Data”
Big data is large, and often times complex, data sets that need to be processed into useful information. Python has emerged over the past few years as a leader in data science programming including the analysis and visualization of large data sets.
Data sets grow rapidly – in part because they are increasingly gathered by cheap and numerous information-sensing internet of things devices such as mobile devices, aerial (remote sensing), software logs, cameras, microphones, radio-frequency identification (RFID) readers and wireless sensor networks. The world’s technological per-capita capacity to store information has roughly doubled every 40 months since the 1980s; as of 2012, every day 2.5 exabytes (2.5×1018) of data are generated. Based on an IDC (International Data Corporation) report prediction, the global data volume will grow exponentially from 4.4 zettabytes to 44 zettabytes between 2013 and 2020. By 2025, IDC predicts there will be 163 zettabytes of data.[1]
An example of a successful business that uses python for collecting and analyzing data is ForecastWatch. ForecastWatch.com is in the business of rating the accuracy of weather reports from companies such as Accuweather, MyForecast.com, and The Weather Channel. Over 36,000 weather forecasts are collected every day for over 800 U.S. cities, and later compared with actual climatological data. These comparisons are used by meteorologists to improve their weather forecasts, and to compare their forecasts with others. They are also used by consumers to better understand the probable accuracy of a forecast.[2]
We will use real data from open source data sets (that is saved as text files) for programming practice.
Practice
Problem Statement: Using the text file, NYScoastalFlooding.txt
, identify each of the New York State counties (zones) effected by coastal flooding during the month of August within the dataset provided.
The first step in finding a solution for this problem is to review and understand the format of the data set provided. Open the text in a text editor and note the field headings in the first line of the file. The following is a small sample from the NYScoastalFlooding.txt
file.
YEAR, MONTH_NAME, EVENT_TYPE, CZ_TYPE,CZ_FIPS, CZ_NAME
2017, March, Coastal Flood, Z, 79, NORTHEAST SUFFOLK
2017, March, Coastal Flood, Z, 179, SOUTHERN NASSAU
2017, March, Coastal Flood, Z, 71, SOUTHERN WESTCHESTER
2017, March, Coastal Flood, Z, 81, SOUTHEAST SUFFOLK
2017, October, Coastal Flood, Z, 3, MONROE
2017, October, Coastal Flood, Z, 5, NORTHERN CAYUGA
2017, October, Coastal Flood, Z, 4, WAYNE
2017, October, Coastal Flood, Z, 6, OSWEGO
2017, January, Coastal Flood, Z, 79, NORTHEAST SUFFOLK
2017, October, Coastal Flood, Z, 1, NIAGARA
2017, January, Coastal Flood, Z, 179, SOUTHERN NASSAU
We see that the data set has six fields:
- year: Four digit year for the event in this record
- month_name: Name of the month for the event in this record (spelled out; not abbreviated)
- event_type spelled out; not abbreviated
- cz_type: Indicates whether the event happened in a (C) county/parish, (Z) zone or (M) marine
- cz_fips: The county FIPS number is a unique number assigned to the county by the National Institute for Standards and Technology (NIST) or NWS Forecast Zone Number
- cz_name: County/Parish, Zone or Marine Name assigned to the county FIPS number or NWS Forecast Zone
We also notice that all but the first field on each line has a blank space before it (this is important!).
We will break this problem into smaller pieces. Let us start with a program that reads each of the records and keeps a count of the number of records in the file (dataRecordNumb.py). This program is a modification of our readFile.py program.
try:
file1 = open('NYScoastalFlooding.txt ','r') # try to find & open the file
except:
print('ERROR: unable to open or locate the file')
else:
count = 0 # Initialize recount cout to zero
for line in file1: # Read each line as text
print(line.strip()) # Print the record
count = count + 1 # increment record counter
print("There are",count,"data records in this file")
file1.close() # Close the file after processing data
The last line of the output from running this program:
RESTART: C:/Users/lh166266.UALBANY/Code/dataRecordNumb.py
There are 61 data records in this file
>>>
Recall from Unit 2 when we used the split()
method to identify each individual word in a sentence. What the method does is split or breakup a string and add the data to a list of separate ‘chunks’ using a defined separator. So if this line is read
2017, January, Coastal Flood, Z, 79, NORTHEAST SUFFOLK
and we split the line into individual fields we could identify those records effected by coastal flooding during the month of August.
fields = line.split(‘,’)
If we now print fields we have a list of all the fields which we can now access.
>>> print(fields)
['2017', ' January', ' Coastal Flood', ' Z', ' 79', ' NORTHEAST SUFFOLK']
Notice the extra blank space before the string “January” in the list fields
. When trying to identify those records with the string “August” the extra space must be dealt with!
Let us complete the second program to solve the problem of identifying (and print) each of the New York State counties (zones) effected by coastal flooding during the month of August (NYScountiesAug.py
).
# identify each of the New York State counties (zones) effected by coastal flooding during the month of August
print("The following are the NYS counties (zones) effected by coastal flooding during the month of August:")
try:
file1 = open('NYScoastalFlooding.txt ','r') # try to find & open the file
except:
print('ERROR: unable to open or locate the file')
else:
for line in file1: # Read each line as text
fields = line.split(",") # split each line into a list of 'fields'
if fields[1] == " August": # check if the 2nd field is August
county = fields[5] # identify the county from the 6th field
print(county.strip()) # Print the record
file1.close() # Close the file after processing data
The output from running this program:
RESTART: C:/Users/lh166266.UALBANY/Code/NYScountiesAug.py
The following are the NYS counties (zones)
effected
by coastal flooding during the month of August:
OSWEGO
NIAGARA
NORTHERN CAYUGA
JEFFERSON
ORLEANS
MONROE
WAYNE
>>>
To test if the program correctly identified all records effected by coastal flooding during the month of August you would need to manually go through each of the 61 records and flag the records that should be found and printed (or use an app such as Excel to do a sort and count for you).
The actual data set I downloaded had a total of 56,921 records and 51 different fields (a lot more data than what we just worked with!). A professional data scientist would also test her program using a subset of the large data set until she could be satisfied that the program was running correctly and producing the correct results.
Unit Summary
TBD
- Read and write programs using the Python IF and IF/ELIF/ELSE statements to implement a simple decision structures.
- Write simple exception handling code to catch simple Python run-time errors.
- Read and write programs using the Python FOR and WHILE statements to implement a simple loop structures.
- Construct and implement algorithms that use decision and loop structures.
- Apply basic file processing concepts and techniques for reading and writing text files in Python.
Practice Problems
- Write a program to accept a number from the user and print whether it is positive or negative.
- Accept three numbers from the user and print the greatest number.
- Write a program that accepts a number in the range from 1 to 7 from the user and generates and displays the name of the weekday.
- Write a program to input 5 numbers from the user and calculates and displays their sum and average.
- Write a program that accepts an integer number and indicates whether it is negative, zero, or positive. Force the user to enter only valid data (repeatedly ask the user to enter only an integer number)
- Provide the exact sequence of integers specified by each of the following range expressions.
- range(5)
- range(5, 10)
- range(5, 20, 3)
- range(20, 5, -1)
- range(20, 5, -3)
- range(10, 5)
- range(0)
- range(10, 101, 10)
- range(10, -1, -1)
- range(-3, 4)
- range(0, 10, 1)
- Write a program to print a pattern like a right angle triangle with numbers where each number will repeat in a row. The pattern is as follows:
1
22
333
4444
55555 - Write a program to print a pattern like a pyramid with numbers where each number will repeat in a row. The pattern is as follows:
- Find a poem you like and save it as a text file named poem.txt. Write a program that counts the number of lines in your program. Print out the line count and each individual line in the program (no extra blank lines!)
- Write a program that stores the first 100 integers to a text file named numbers.txt. Each number should appear on a line all by itself.
- Write a program to find the longest word in a text file.