Don Miner & Sue Evans

Adapted from the CS1 Course at Swarthmore College by Lisa Meeden

*Hit the space bar for next slide*

- Understand that many problems require using repeated code.
- Understand that for loops are used to iterate over sequences.
- Familiarity with using nested for loops for 2 dimensional data.
- Understand while loops, including sentinel loops and post-test loops.
- Familiarity with the terms: priming read, sentinel, continuation condition, termination condition, iteration, and loop control variable.
- Understand reading from files using while loops and for loops.
- Be aware that break and continue damage readability and alter typical program flow.
- Be aware of possible loop control problems due to inaccuracy of floating point numbers and binary storage.

- We've already used the simplest of for loops that iterates a specified
amount of times. Recall that it can use the
`range`function and when it does, it has the form:

for <variable> in range(<iterations>): <code block>

>>> for i in range(6): ... print i, ... 0 1 2 3 4 5

>>> def count(number): ... for i in range(number + 1): ... print i, ... >>> count(15) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

`range`assumes you want to start counting at 0. We can change this by giving it two parameters: a start number and a stopping number (plus one).- Note:
`range`stopping at the number minus one will make more sense when we talk about iterating over lists. - For example:

>>> def count(start, stop): ... for i in range(start, stop + 1): ... print i, ... >>> count(11, 15) 11 12 13 14 15

>>> def countBy2(start, stop): ... for i in range(start, stop + 1, 2): ... print i, ... >>> countBy2(11, 15) 11 13 15

>>> def countBack(start, stop): ... for i in range(start, stop - 1, -1): ... print i, ... >>> countBack(9, 4) 9 8 7 6 5 4

- What are the factors of some number, n ?
- Let's loop over all numbers less than n and see if they'll divide evenly into it.
- We'll use the modulus operator % that returns the remainder of a division:

>>> 5 % 4 1 >>> # will return 0 because 2 divides 10 evenly ... 10 % 2 0 >>> 9 % 5 4

>>> def factors(n): ... for i in range(2, n): ... if n % i == 0: ... print i, ... >>> factors(30) 2 3 5 6 10 15

- For loops can iterate over lists, strings and other
*sequences*. - We will learn more about sequences later.
- We can iterate character by character through a string. Lets add a space between each character:

>>> word = "hello world" >>> for c in word: ... print c, ... h e l l o w o r l d

>>> myList = [32, 45, 34, 76, 45] >>> sum = 0.0 >>> for n in myList: ... sum += n ... >>> print sum / len(myList) 46.4

>>> print range(1,5) [1, 2, 3, 4]

- For loops can be nested, meaning you can have a for loop inside of another for loop.
- For example, lets make a multiplication table:

>>> for i in range(1, 5): ... for j in range(1, 5): ... print i, '*', j, '=', i * j, '\t', ... print ... 1 * 1 = 1 1 * 2 = 2 1 * 3 = 3 1 * 4 = 4 2 * 1 = 2 2 * 2 = 4 2 * 3 = 6 2 * 4 = 8 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9 3 * 4 = 12 4 * 1 = 4 4 * 2 = 8 4 * 3 = 12 4 * 4 = 16

You may not use Python's repetition operator, *, for this exercise.

You must prompt the user in main() for the length of a side.

- Write nested for loops in a function called square(length)
that will print a square box with the number of stars given by the
length passed in.
* * * * * * * * * * * * * * * * * * * *

In this case, length was 6. - Write nested for loops in a function called triangle(length)
that will print an isoceles right triangle like this one which has
the number of stars given by the length passed in.
* * * * * * * * * * * * * * *

In this case, length was 6.

- Sometimes we don't know ahead of time when a loop should end, so we can't use a for loop.
- We can use a
`while`loop, which loops until a condition is met. - while loops have the form:

while <condition>: <body>

>>> n = 0 >>> while 2 ** n < 1000: ... print '2 **', n, '=', 2 ** n, 'and is < 1000.' ... n = n + 1 ... 2 ** 0 = 1 and is < 1000. 2 ** 1 = 2 and is < 1000. 2 ** 2 = 4 and is < 1000. 2 ** 3 = 8 and is < 1000. 2 ** 4 = 16 and is < 1000. 2 ** 5 = 32 and is < 1000. 2 ** 6 = 64 and is < 1000. 2 ** 7 = 128 and is < 1000. 2 ** 8 = 256 and is < 1000. 2 ** 9 = 512 and is < 1000. >>> print 2 ** n 1024 >>>

- While loops are good for implementing
*interactive loops*. - Interactive loops can get an unspecified amount of input from a user by asking the user if s/he has more.
- For example, consider the following program that asks a user for numbers then averages them. It uses the accumulator pattern to accumulate two things, the sum and and the number of items.
`input`and`raw_input`both take keyboard input from the user, but they return different things.`raw_input`always returns a string that is exactly what the user typed in.`input`tries to evaluate the input, as if it were typed into the Python shell.- Here's some example input/output:

print "This program finds the average of numbers you enter\n" sum = 0.0 count = 0 moreData = "yes" # Why do we have to check the length > 0 ? while len(moreData) > 0 and moreData[0] == "y": x = input("Enter a number: ") sum = sum + x count = count + 1 moreData = raw_input("Do you have more numbers (yes or no)? ") if count == 0: print "\n Sorry you didn't want to run this program" else: print "\nThe average of the numbers is", sum / count

This program finds the average of numbers you enter Enter a number: 32 Do you have more numbers (yes or no)? yes Enter a number: 45 Do you have more numbers (yes or no)? y Enter a number: 34 Do you have more numbers (yes or no)? y Enter a number: 76 Do you have more numbers (yes or no)? y Enter a number: 45 Do you have more numbers (yes or no)? nope The average of the numbers is 46.4

- Sentinel loops are the same as interactive loops, except that they wait for a specific number as input, then stop.
- The
**sentinel**is the value that will cause the loop to stop. - Sentinel loops have the following general form:
get the first data item while item is not the

*sentinel*: process the item get the next data item - Notice that we need to get the first data item before we enter the
loop. This is known as doing the
**priming read**. - For example, we can reimplement our interactive loop as a sentinel loop:
- Here's some sample input/output:

# Filename: sentinel.py # Author: Don Miner & Sue Evans # Date: 8/9/09 # Section: All # Email: bogar@cs.umbc.edu # Description: This program illustrates use of a sentinel # loop with a priming read. It also shows # the use of a constant. def main(): print "This program finds the average of numbers you enter\n" sum = 0.0 count = 0 # QUESTION is in all caps because it's a constant # Using constants can save a lot of typing QUESTION = "Enter a number (0 to quit): " # priming read x = input(QUESTION) # sentinel loop using a sentinel of 0 while x != 0: sum += x count += 1 x = input(QUESTION) if count == 0: print "\n Sorry you didn't want to run this program" else: print "\nThe average of the numbers is", sum / count main()

This program finds the average of numbers you enter Enter a number (0 to quit): 32 Enter a number (0 to quit): 45 Enter a number (0 to quit): 34 Enter a number (0 to quit): 76 Enter a number (0 to quit): 45 Enter a number (0 to quit): 0 The average of the numbers is 46.4

- What if we made a mistake near the end of inputting a lot of data ?
- What if we had to read in 10,000 numbers ?
- What if there is no good sentinel value ?
- We could read from a file !

If the numbers are in a file, we don't have to worry about typos, or how many numbers there are, or having a good sentinel. - Here's a sample data file,
`data.dat`

12 21 35 -5 90 75 59 -23 40 0 57 32 -12 45 61 110 94 37 77 31 99 38 47 76 17

infile = open(<file name>, <mode>)

line = infile.readline()

# Filename: filewhile.py # Author: Don Miner & Sue Evans # Date: 8/9/09 # Section: All # Email: bogar@cs.umbc.edu # Description: This program illustrates use of a while # loop to read from a file and stop at # the end-of-file. def main(): print "This program finds the average of numbers found in a file\n" fileName = raw_input("What file are the numbers in ? ") infile = open(fileName, "r") sum = 0.0 count = 0 # priming read - read the first line line = infile.readline() # readline() will return "" when the file is done while line != "": # float(n) tries to convert whatever n is to a float sum += float(line) count += 1 line = infile.readline() if count == 0: print "\n Sorry you didn't want to run this program" else: print "\nThe average of the numbers is", sum / count main()

linuxserver1.cs.umbc.edu[123] python filewhile.py This program finds the average of numbers found in a file What file are the numbers in ? data.dat The average of the numbers is 44.52 linuxserver1.cs.umbc.edu[124]

# Filename: filefor.py # Author: Don Miner & Sue Evans # Date: 8/9/09 # Section: All # Email: bogar@cs.umbc.edu # Description: This program illustrates use of a for # loop to read from a file and stop at # the end-of-file. def main(): print "This program finds the average of numbers found in a file\n" fileName = raw_input("What file are the numbers in ? ") infile = open(fileName, "r") sum = 0.0 count = 0 # Python automatically goes line-by-line for line in infile: # float(n) tries to convert whatever n is to a float sum += float(line) count += 1 if count == 0: print "\n Sorry you didn't want to run this program" else: print "\nThe average of the numbers is", sum / count main()

linuxserver1.cs.umbc.edu[125] python filefor.py This program finds the average of numbers found in a file What file are the numbers in ? data.dat The average of the numbers is 44.52 linuxserver1.cs.umbc.edu[126]

- In a situation where a user is giving input, sometimes we would like to keep asking the user until s/he gives us valid input.
- To do this, we would use a
**post-test loop**, which iterates until the condition has been satisfied. - For example, we want to get input from the user until s/he provides us with a positive number :
- Notice that an alternative to using a priming read with a while loop, is to start with an illegal value to get into the loop. This is a common practice with post-test loops
- A good example using a post-test loop is the function getValidInt() shown below :

# start with an illegal value to get into the loop number = -1 while number < 0: number = input("Enter a positive number : ")

# Filename: getValidInt.py # Author: Sue Evans # Date: 8/9/09 # Section: All # Email: bogar@cs.umbc.edu # Description: This program illustrates use of a while # loop to get values from the user within # a specified range, rejecting all bad input. # The function uses a post-test loop. def getValidInt(question, min, max): # use a bad value to enter the loop value = max + 1 # compose the prompt prompt = question + " (" + str(min) + "-" + str(max) + "): " # continue to get values until the user enters a valid one while value == "" or value < min or value > max: value = raw_input(prompt) if len(value) != 0: value = int(value) # return a valid value return value def main(): print "\nThis program will give the classifications" print "of integers in the range you select.\n" START_QUES = "Enter the starting integer" END_QUES = "Enter the ending integer" start = getValidInt(START_QUES, 1, 10000) stop = getValidInt(END_QUES, start, 10000) print "\nYou selected %d to %d.\n" % (start, stop) main()

Let's watch it work.

linuxserver1.cs.umbc.edu[121] python getValidInt.py This program will give the classifications of integers in the range you select. Enter the starting integer (1-10000): 10001 Enter the starting integer (1-10000): 0 Enter the starting integer (1-10000): Enter the starting integer (1-10000): -2 Enter the starting integer (1-10000): 5 Enter the ending integer (5-10000): 4 Enter the ending integer (5-10000): 10001 Enter the ending integer (5-10000): 23 You selected 5 to 23. linuxserver1.cs.umbc.edu[122]

- The following program uses many of the types of loops we've been studying.
`main()`uses a sentinel loop.- The function
`getValidInt()`uses a post-test loop. - The function
`drawRectangle()`uses nested for loops. - A common way of interacting with the user is to use a
**menu**. Here's a program that works with rectangles and uses a menu :

# Filename: rectangles.py # Author: Sue Evans # Date: 8/12/09 # Section: all # Email: bogar@umbc.edu # # This program uses a menu to interact with the user. # It also makes use of functions. # findArea() finds the area of a rectangle # Inputs: length and width # Output: the area of the rectangle def findArea(length, width): return length * width # findPerimeter() finds the perimeter of a rectangle # Inputs: length and width # Output: the perimeter of the rectangle def findPerimeter(length, width): return 2 * (length + width) # drawRectangle() draws the rectangle using *s # Inputs: length and width # Output: none def drawRectangle(length, width): print for i in range (0, length): for j in range (0, width): # if it's on the border print a star else a space if i == 0 or j == 0 or i == length - 1 or j == width - 1: print '*', else: print ' ', print # enterDimensions() allows the user to enter # the dimensions of a rectangle. # Inputs: none # Output: length and width def enterDimensions(): length = getValidInt("Enter the length", 1, 10) width = getValidInt("Enter the width", 1, 10) return length, width # getValidInt() prompts the user to enter an # integer in the specified range, rejects values # not in that range by requiring new input, and # only returns a valid integer. # Inputs: the question of the prompt, # the minimum value in the range # and the maximum value in the range # Output: an integer in the specified range def getValidInt(question, min, max): # use a bad value to enter the loop value = max + 1 # compose the prompt prompt = question + " (" + str(min) + "-" + str(max) + "): " # continue to get values until the user enters a valid one while value == "" or value < min or value > max: value = raw_input(prompt) if len(value) != 0: value = int(value) # return a valid value return value # printMenu() prints the menu of choices # Inputs: none # Output: none def printMenu(): print "\n\tE - Enter a rectangle's dimensions\n" print "\tA - Find the area of the rectangle\n" print "\tP - Find the perimeter of the rectangle\n" print "\tD - Draw the rectangle\n" print "\tQ - Quit\n\n" # printGreeting() prints the greeting to the user # Inputs: none # Output: none def printGreeting(): print "\nThis program works with rectangles." print "It can find the area and perimeter of a rectangle" print "whose dimensions you've entered and can even draw it." print "You can continue to enter as many rectangles as you want.\n" def main(): choice = '' printGreeting() length, width = enterDimensions() while choice != 'Q' and choice != 'q': printMenu() choice = raw_input("Enter your choice : ") if choice == 'E' or choice == 'e': length, width = enterDimensions() elif choice == 'A' or choice == 'a': area = findArea(length, width) print "The area of a %d x %d" % (length, width), print "rectangle is %d\n\n" % area elif choice == 'P' or choice == 'p': perimeter = findPerimeter(length, width) print "The perimeter of a %d x %d" % (length, width), print "rectangle is %d\n\n" % perimeter elif choice == 'D' or choice == 'd': drawRectangle(length, width) elif choice == 'Q' or choice == 'q': print else: print choice + ' is not a valid choice\n' main()

Let's see it run.

linuxserver1.cs.umbc.edu[101] python rectangles.py This program works with rectangles. It can find the area and perimeter of a rectangle whose dimensions you've entered and can even draw it. You can continue to enter as many rectangles as you want. Enter the length (1-10): 4 Enter the width (1-10): 7 E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : a The area of a 4 x 7 rectangle is 28 E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : p The perimeter of a 4 x 7 rectangle is 22 E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : D * * * * * * * * * * * * * * * * * * E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : E Enter the length (1-10): 9 Enter the width (1-10): 4 E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : d * * * * * * * * * * * * * * * * * * * * * * E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : w w is not a valid choice E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : e Enter the length (1-10): 12 Enter the length (1-10): 4 Enter the width (1-10): 10 E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : d * * * * * * * * * * * * * * * * * * * * * * * * E - Enter a rectangle's dimensions A - Find the area of the rectangle P - Find the perimeter of the rectangle D - Draw the rectangle Q - Quit Enter your choice : q linuxserver1.cs.umbc.edu[102]

`break`can be used to exit the current loop.- For example, we can rewrite our sentinel average example so that it doesn't need a priming read :
- What happens if we wrote the if statement wrong and it never evaluates to true?
`break`also works with for loops.- Although
`break`works, it should be avoided because it damages the readability of your code. Programmers expect to see the real**continuation condition**behind the word`while`. Using`while True`with a`break`somewhere within the loop causes the reader to go through the whole body of the loop to see what the**termination condition**is. - Use of
`break`is not allowed in CMSC 201. See the class standards.

sum = 0.0 count = 0.0 while True: x = input("Enter a number (0 to quit): ") # if x is 0 we'll stop this loop now if x == 0: break sum = sum + x count = count + 1 print "\nThe average of the numbers is", sum / count

- Sometimes, we may want to skip part of a loop.
- In the case of the for loop, when the
`continue`is encountered, the next value will be placed into the**loop control variable**and the next**iteration**will begin. An**iteration**is one time through the loop. - For example, lets write a for loop that prints out numbers that are divisible by 3 or 7:

>>> for n in range(30): ... if not (n % 3 == 0 or n % 7 == 0): ... continue ... print n, ... 0 3 6 7 9 12 14 15 18 21 24 27 28

# Filename: beers.py # Author: An unknown UMBC student # Date: Every semester # Section: Can never remember # Email: unknown@umbc.edu # # How many beers are left after 5 rounds? def main(): beers = 1.0 CHORUS = 'bottles of beer' # You'd think this loop will count down from 1.0 to 0.0 by # step -0.2, singing each verse as it goes, but does it ? while beers != 0.0: print "%f %s on the wall" % (beers, CHORUS) print "%f %s" % (beers, CHORUS) print "Take a fifth down, pass it around" beers -= 0.2 print "%e %s on the wall\n" % (beers, CHORUS) main()

linuxserver1.cs.umbc.edu[101] python beers.py 1.000000 bottles of beer on the wall 1.000000 bottles of beer Take a fifth down, pass it around 8.000000e-01 bottles of beer on the wall 0.800000 bottles of beer on the wall 0.800000 bottles of beer Take a fifth down, pass it around 6.000000e-01 bottles of beer on the wall 0.600000 bottles of beer on the wall 0.600000 bottles of beer Take a fifth down, pass it around 4.000000e-01 bottles of beer on the wall 0.400000 bottles of beer on the wall 0.400000 bottles of beer Take a fifth down, pass it around 2.000000e-01 bottles of beer on the wall 0.200000 bottles of beer on the wall 0.200000 bottles of beer Take a fifth down, pass it around 5.551115e-17 bottles of beer on the wall 0.000000 bottles of beer on the wall 0.000000 bottles of beer Take a fifth down, pass it around -2.000000e-01 bottles of beer on the wall -0.200000 bottles of beer on the wall -0.200000 bottles of beer Take a fifth down, pass it around -4.000000e-01 bottles of beer on the wall -0.400000 bottles of beer on the wall -0.400000 bottles of beer Take a fifth down, pass it around -6.000000e-01 bottles of beer on the wall -0.600000 bottles of beer on the wall -0.600000 bottles of beer Take a fifth down, pass it around -8.000000e-01 bottles of beer on the wall

I had to stop this code from running using ^c

It's an endless loop.

**Don't test floating point numbers for equality.**- The culprit: 1/5 is not a terminating fractional number in base 2

(similar to 1/3 in base 10). 1/5_{10}= 0.001100110011..._{2}repeating.