block-beta
columns 4
space
title["Breakdown of a While"]:2
space
block:Input
columns 1
while["while"]
whileDescr["(start of the while construction)"]
end
block:MiddleOne
columns 1
condition["condition"]
conditionDescr["(value that is True or False)"]
end
block:MiddleTwo
columns 1
colon[":"]
colonDescr["Colon"]
end
block:Suite
columns 1
suite["Statement block"]
suiteDescr["(statements)"]
end
classDef BG stroke:transparent, fill:transparent
class title BG
class condition BG
class conditionDescr BG
class colon BG
class colonDescr BG
class while BG
class whileDescr BG
class suite BG
class suiteDescr BG
Chapter 6: Repeating Actions with Loops
Notes
The while construction
whileallows a program to repeat blocks of statements- structure is similar to an
if
- if the condition evaluates
Truethen the block of statements is run- After the statements are run, control returns to the start of the
whileloop - If the condition is still
Truethen the loop runs again
- After the statements are run, control returns to the start of the
Code Analysis: Investigating the while construction
Use the python interpreter to run the following to understand the while loop
Can we use a boolean value to control a
whileconstruction?- Yes, for example the block of statements in the
whilehere shouldn’t run
while False: print("Loop") print("Outside the Loop")Outside the Loop- Yes, for example the block of statements in the
Can a loop go on forever?
- Yes, an control expression for a
whilethat always evaluatesTruewill cause the loop to run infinitely
while True: print("Loop") print("Outside the Loop")- The above should only print
"Loop"when executed - If you accidentally do this you may need to use
CTRL+C,CTRL+Zor an interrupt execution feature of your live environment to stop the execution
- Yes, an control expression for a
Will the following program ever print out the message,
"Outside loop"?while True: print("Inside Loop") print("Outside Loop")- No, the above is a quintessential infinite loop
Will the following program ever print out the message,
"Inside Loop"? How about"Outside loop"?while False: print("Inside Loop") print("Outside Loop")Outside Loop- The
whilenever executes the statements inside so"Inside Loop"is never printed, but"Outside Loop"is.
- The
What will the following program print?
# Example 6.1 Loop with Flag # # Demonstrates control of a loop with a boolean flag flag = True while flag: print("Inside Loop") flag = False print("Outside Loop")Inside Loop Outside Loop- When we first enter the loop
flagisTrueso the loop executes and*"Inside Loop"is printed flagis then setFalseso on the next iteration of the loop, the loop doesn’t execute.- We move to the next statement outside of the loop and print out
"Outside Loop" - The pattern of using a control variable that is updated in the loop body in a
whileloop is very common
- When we first enter the loop
What will the following program print?
flag = True while flag: print("Inside Loop") Flag = False print("Outside Loop")- This looks similar to the previous, but note the typo, we refer to
Flagnotflaginside the loop - This which defines a new variable, instead of modifying the loop control.
- We thus get an infinite series of
"Inside Loop"being printed.
- This looks similar to the previous, but note the typo, we refer to
What will the following program print?
# Example 6.2 Loop with Counter # # Demonstrates use control of a while loop # using a conditional expression count = 0 while count < 5: print("Inside Loop") count = count + 1 print("Outside Loop")Inside Loop Inside Loop Inside Loop Inside Loop Inside Loop Outside Loopcountis initially set to \(0\)- At each iteration we print
"Inside Loop"* and increase the value ofcountby \(1\) - The loop stops once
countreaches \(5\) - This means that
"Inside Loop"should be printed \(5\) times, followed by"Outside Loop"
Make Something Happen: Create a Looping Selection Program
Use a while loop, to make a theme park selector that runs continuously. All you need to do is put all of the statements that implement the theme park behaviour into a while True construction
For usability our program won’t loop endlessly. We’ll say that any number that it is not a valid ride number is code for quitting the program. The relevant changes to the Ride Selector are then,
# Exercise 6.1 Looping Ride Selector
#
# Wraps the Ride Selector Program in a while
# loop to allow the user to look at multiple rides
run_program = True
while run_program:
print("""Welcome to our Theme Park
These are the available ride:
1. Scenic River Cruise
2. Carnival Carousel
3. Jungle Adventure Water Splash
4. Downhill Mountain Run
5. The Regurgitator
Any other number to quit...
""")
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
if ride_number < 1 or ride_number > 5:
run_program = False
elif ride_number == 1:Observe that first we wrap all of the code in a while loop, and introduce a boolean flag run_program initially set to True to flag if the program continues to run at each loop iteration. When a user enters a number we first check if it corresponds to a ride number and if not, we set the program to quit on the next loop iteration by setting run_program to False. We now change the original if ride_number == 1 to and elif so it is only checked if we know the ride_number is valid. (The full code is in LoopingRideSelector.py)
Make Something Happen: Create a Looping Countdown Program
One of the examples in the above question set involved a countup to \(5\). Implement a program that counts down from \(10\) to \(0\) over \(10\) seconds
# Exercise 6.2: Countdown
#
# Performs a 10-second countdown
import time
time_left = 10
while time_left >= 0:
print(time_left)
time_left = time_left - 1
time.sleep(1)10
9
8
7
6
5
4
3
2
1
0
This is a straightforward exercise (see Countdown.py), we set up our counter value to \(10\) and use the appropriate loop expression (here time_left >= 0) to ensure that \(0\) is included in the countdown.
In the loop we print the current value of time_left, then decrement time_left by \(1\), and sleep for the required time. Observe that after the program prints \(0\), time_left becomes \(-1\) and the next iteration of the loop won’t run.
Handling Invalid User Entry
- Ride Selector doesn’t account for invalid user entry
- Blindly assumes a number outside the range \(1\) to \(5\) represents quitting the program
- Ideally we would like to have a distinct number that represents quitting and a way to capture and handle any invalid inputs
Great Programmers Think Defensively
Defensive programming is a programming technique in which a programmer attempts to defend their code against possible errors that might occur in a code e.g. receiving a word when expecting a number
It is good practice to think about, typically a user expects a computer to do something reasonable even when provided unreasonable input.
Data validation does have the downside in that it can make programs significantly bigger, and in compiled languages knowing that data is valid can make them much faster. A good skill is learning the correct layers or boundaries of a program to perform the defensive data validation so the core can run without concern
Ignoring the question of quitting for now, data validation for the ride selector might look like,
if ride_number < 1 or ride_number > 5: print('Invalid ride number')
Make a Loop to Validate Input
Above acknowledges the error, but if we want to use this in our loop control we will need to use
whileride_number_text = input("Please enter the ride number you want: ") ride_number = int(ride_number_text) while ride_number < 1 or ride_number > 5: print("There is no ride with that number") ride_number_text = input("Please enter the ride number you want: ") ride_number = int(ride_number_text) print("You have selected ride number: ", ride_number)whilemeans program repeats until it receives valid input- Observe the downside
- We have to repeat the code asking for the ride number and converting to an integer
- Some languages have a
do ... whilestatement which performs its test after executing the loop body for the first time- Would allow us to write the above as one construct
Make Something Happen: Add Ride Number Validation to the Theme Park Ride Selector
Add ride number validation to the Looping Ride Selector implementation. Remember that the while construction must be added after the ride_number value has been read by the program
We can basically add the validation in immediately after the first attempt to read the ride number from the user. We also have to adjust the code to now use \(0\) as the explicit value for quitting rather than inferring any non-ride-number as a quit value. The main changes are,
# Exercise 6.3 Ride Selector with Ride Number Validation
#
# Adds Ride Number validation to the Ride Selector
# The program will query the user until a valid ride number or
# the quit number is given
while run_program:
print("""Welcome to our Theme Park
These are the available ride:
1. Scenic River Cruise
2. Carnival Carousel
3. Jungle Adventure Water Splash
4. Downhill Mountain Run
5. The Regurgitator
Press 0 to quit the program
""")
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
while ride_number < 0 or ride_number > 5:
print("There is no ride with that number")
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
if ride_number == 0:
run_program = FalseThe complete code is given in RideNumberValidation.py
Code Analysis: When good loops go bad
When creating composite conditions for loops, making sure the logic is correct is incredibly important. Examine the following program to understand more complicated loop control
age_text = input("Please enter your age: ")
age = int(age_text)
while age < 1 and age > 95:
#repeat this code while the age is invalid
print("This age is not valid")
age_text = input("Please enter your age: ")
age = int(age_text)
#when we are here, we have a valid age value
print("Thank you for entering your age")- What is the fault in this program?
- The condition
age < 1 and age > 95requiresageto be both less than \(1\) and greater than \(95\), this is impossible, so the loop never runs
- The condition
- What will the fault cause the program to do?
- Since the loop body can never run, every entered age will be considered valid
- How do you fix this?
The desired logic is that
ageshould be between \(1\) and \(95\) inclusive. This logic is captured by theoroperator.The corrected expression is*
while age < 1 or age > 95
Always test failure behaviours along with successful ones
It’s very important when testing software to test both the successful path (the so-called “happy path”) and any possible error states.
A good programmer proactively looks for potential points of failure, writes code to handle the errors and importantly checks that the code to handle the errors does what it’s supposed to do
A good heuristic for starting to do this with simple programs is called boundary-value testing. Boundaries are the points between different expected behaviours. For example with the ride selector, we expect different behaviour for numbers \(< 1\) or \(> 5\) to those in the range \(1\) to \(5\). So a good set of tests might be \(0\), \(1\), \(2\), \(4\), \(5\), \(6\). i.e. we test either side of the boundary, and on the boundary
Make Something Happen: Add Validation to the Theme Park Age Input
Add age validation to the Ride Selection Program. The theme park owner has told you that the minimum age for anyone going on a ride at the theme park is \(1\) year, and the maximum age is \(95\). Use these values in your program
Observe that in this case if the user provides an age outside the accepted range, we don’t want to prompt them to put in a new age, since this could legitimately be their age. Instead we want to tell them regardless of the ride they chose they can’t ride. In this case we should use an if style validation technique
The change is applied at our age reading section of the program, we use an if...elif...else construct to tell the user they are either too young, too old, or to continue on to the standard ride selection code
age_text = input("Please enter your age: ")
age = int(age_text)
if age < 1:
print("You are too young to go on any rides")
elif age > 95:
print("You are too old to go on any rides")
else:
#continue on to normal ride selection code...The full code is given in AgeValidation.py
Detect Invalid Number Entry using Exceptions
- Problem: We can easily write a loop that checks if a value is invalid but how do we deal with the type being invalid?
- e.g. in the ride selector how do we deal with the user typing in a word rather than a number?
- Consider the snippet below, emulating the ride selector given a string input, we get an error, before we even get a chance to validate the value
ride_number_text = "three" ride_number = int(ride_number_text)--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[6], line 2 1 ride_number_text = "three" ----> 2 ride_number = int(ride_number_text) ValueError: invalid literal for int() with base 10: 'three'
- This occurs because
intrequires it’s input to be convertible to a number- Unfortunately this does not extend to human-language written versions of a number
- In this case
intthrows an error, it is better to end the program than continue in an erroneous state
- In general, when a program encounters an error state, it should aim to fail fast, rather than continue and generate unexpected outcomes
- Exceptions are a mechanism by which elements of a program can inform other parts about errors that have occurred
- Exceptions combine a description of what the error that occurred was, with where the error occurred
- In the example above e.g. we are told that we got a
ValueError - i.e. an invalid value was found, we are given the additional detail “invalid literal for int() with base 10: ‘three’”
- In plain english, the program did not know how to convert ‘three’ to an integer
- We are also told where, in this case the second line, in the function
int
- To recover from an exception we have to handle it, i.e. do something
- The first step is to catch the exception
- We wrap code that might throw an exception in a
try... exceptblock
# Example 6.3: Catching Exceptions # # Demonstrates how to catch and handle # an exception try: ride_number_text = input("Please enter a ride number: ") ride_number = int(ride_number_text) #statement that might raise exception print("You have entered", ride_number) except ValueError: # Start of an exception handler print("Invalid number") # Performed if exception raised - We wrap the code that may throw an exception in a
try - We then use
exceptto define statements we want to run if an exception is thrown- If an exception is thrown, control immediately jumps to the
exceptblock - e.g. In the above example if
intthrows aValueErrorthen the lineprint("You have entered", ride_number)won’t run- Instead
print("Invalid number")runs
- Instead
- If an exception is thrown, control immediately jumps to the
- As observed
exceptis followed by the exception type we want to catch (in this caseValueError) - The full example is given in CatchingExceptions
block-beta
columns 4
space
title["Breakdown of a Try-Except Block"]:2
space
block:Try:2
columns 1
try["try"]
tryDescr["(start of the try construction)"]
end
block:TryColon
columns 1
Trycolon[":"]
TryColonDescr["colon"]
end
block:TrySuite
columns 1
Trysuite["Statements"]
TrysuiteDescr[("statements to execute normally")]
end
classDef BG stroke:transparent, fill:transparent
class title BG
class try BG
class tryDescr BG
class Trycolon BG
class TryColonDescr BG
class Trysuite BG
class TrysuiteDescr BG
block:ExceptOne
columns 1
exceptOne["except"]
exceptOneDescr["(start of an exception construction)"]
end
block:ExceptNameOne
columns 1
exceptOneName["Name"]
exceptOneNameDescr["(exception name)"]
end
block:ExceptOneColon
columns 1
exceptOneColon[":"]
exceptOneColonDescr["colon"]
end
block:ExceptOneStatements
columns 1
exceptOneStatements["statements"]
exceptOneStatementsDescr[("statements to execute if exception caught")]
end
class exceptOne BG
class exceptOneDescr BG
class exceptOneName BG
class exceptOneNameDescr BG
class exceptOneColon BG
class exceptOneColonDescr BG
class exceptOneStatements BG
class exceptOneStatementsDescr BG
block:ExceptTwo
columns 1
exceptTwo["except"]
exceptTwoDescr["(start of an exception construction)"]
end
block:ExceptNameTwo
columns 1
exceptTwoName["Name"]
exceptTwoNameDescr["(exception name)"]
end
block:ExceptTwoColon
columns 1
exceptTwoColon[":"]
exceptTwoColonDescr["colon"]
end
block:ExceptTwoStatements
columns 1
exceptTwoStatements["statements"]
exceptTwoStatementsDescr[("statements to execute if exception caught")]
end
class exceptTwo BG
class exceptTwoDescr BG
class exceptTwoName BG
class exceptTwoNameDescr BG
class exceptTwoColon BG
class exceptTwoColonDescr BG
class exceptTwoStatements BG
class exceptTwoStatementsDescr BG
- As demonstrated above a
try...exceptblock may contain multipleexceptstatements designed to handle different exception types
Exceptions and Number Reading
- We’ve seen how to use loops to handle invalid values
- We’ve seen how to use exceptions to handle invalid types
- Now let’s put that together to write a loop to handle exceptions
Code Analysis: Handling Exceptions in Loops
We want to make a program that will perform a while construction as long as the user keeps typing in text that cannot be converted into a number. Look at the example code below, (see HandlingInvalidText.py) and answer the questions
# Example 6.4: Handling Invalid Text
#
# Combines loops and exception handling to prompt a user
# for a valid number and repeat until a number is provided
ride_number_valid = False # create and set a flag to False
while not ride_number_valid: # repeats while flag is False
try:
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text) # can throw a ValueError
ride_number_valid = True # successfully read a number
except ValueError: # catch the ValueError
print("Invalid number. Please enter a number in digits")
# Once outside the loop we have a valid number
print("You have selected ride", ride_number)- What is the purpose of the variable,
ride_number_valid?- It is a flag
- Tracks the state of a program, in this case a valid number been read
- Starts
Falseonce successfully received anintflips toTrue
- How many times would you expect the
whileconstruction to loop when the program is used?- Ideally we would expect it to run once
- i.e. The user enters a number straight away
- In the next best case we would expect it run twice
- The user experiences an error, reads the message and corrects their input the next time
- Ideally we would expect it to run once
- Why don’t we have to test
ride_number_validat line \(10\), to make sure that the ride number is valid?- The while loop stops when it’s condition is
False - This corresponds to
ride_number_valid = True - So we know that once we leave the loop
ride_number_validmust beTrue
- The while loop stops when it’s condition is
Handling Multiple Exceptions
- Sometimes there a multiple exception types we wish to handle
- e.g. a
KeyboardInterruptallows a user to issue an exception which could stop a program- If the user is interacting with somebody else’s external facing program, we might not want them to be able to do this
- Simultaneously we might need to ensure that the user inputs valid data like numbers
- We can just add an additional
exceptblock- When an exception is thrown, the appropriate handler takes control
- The improved exception handling code is given in HandlingInvalidTextMultipleExceptions
# Example 6.5: Improved Handling Invalid Text
#
# Extends Example 6.4 by preventing the user from issuing a
# keyboard interrupt to stop the program
ride_number_valid = False # create and set a flag to False
while not ride_number_valid: # repeats while flag is False
try:
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text) # can throw a ValueError
ride_number_valid = True # successfully read a number
except ValueError: # catch the ValueError
print("Invalid number. Please enter a number in digits")
except KeyboardInterrupt: # catches the interrupt
print("You do not have permission to interrupt this program")
# Once outside the loop we have a valid number
print("You have selected ride", ride_number) # type: ignorePlan for Failure
When writing a program you should always be thinking about how it could fail and the appropriate response. Any point that asks for user input is a major potential point of failure and should be handled correctly.
You should never catch exceptions to hide errors. You could all statements in a try...except block, but then you can’t identify any errors that occur.
break out of Loops
breakstatements allow you to exit a loop from inside- As soon as a
breakis encountered control immediately jumps to the next statement after the loop - The example code is given in UsingBreakToExitLoops.py
# Example 6.6 Using Break to Exit Loops
#
# Demonstrates using a break statement to exit
# a while loop from inside the loop
while True: # use break rather than a condition to exit
try:
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
break
except ValueError:
print("Invalid number text. Please enter digits")
except KeyboardInterrupt:
print("You do not have permission to interrupt this program")
# Once outside the loop we have a valid number
print("You have selected ride", ride_number) # type: ignore- The above follows the previous example, but uses
breakrather than a flag to control the loop breakstatements can be paired with conditionals likeif, as demonstrated in EarlyExitLoop.py
# Example 6.7 Loop with condition ending early
#
# Demonstrates the pairing of break and conditional
# statements to end a program early
count = 0
while count < 5:
print("Inside Loop")
count = count + 1
if count == 3:
break
print("Outside loop")Inside Loop
Inside Loop
Inside Loop
Outside loop
Don’t use too many break statements
A loop can theoretically only use many break statements to control flow. However break statements make it harder to reason about the flow of a loop. Sometimes they are the cleanest way to do something, but often they just make the code less readable.
In general prefer to use conditions to control loops, they are easier to reason about the state at the end of the loop
Return to the top of a loop with continue
continuecauses control to immediately jump to the start of the next loop iteration- For example consider the Ride Selector example. If a ride is temporarily down we might push a patch to skip any selection of the ride, e.g. IgnoreRide.py given below
# Example 6.8: Ignore Ride
#
# Demonstrates the use of continue to move
# to the next loop iteration, skipping remaining
# loop logic
while True:
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
if ride_number == 3:
print("sorry, this ride is unavailable")
continue
print("you have selected ride number: ", ride_number)You wont use continue as often as you use break
break can be useful in quite a few use cases. continue tends to be much more niche and isn’t used often
Count a Repeating Loop
- You can use a variable to make a loop repeat a specified number of times, e.g. in the below Times Tables Program
# Example 6.9 Times Tables Tutor
#
# Uses Times Tables to demonstrate use of a counter
# variable to control a loop
count = 1
times_value = 2
while count < 13:
result = count * times_value
print(count, "times", times_value, "equals", result)
count = count + 11 times 2 equals 2
2 times 2 equals 4
3 times 2 equals 6
4 times 2 equals 8
5 times 2 equals 10
6 times 2 equals 12
7 times 2 equals 14
8 times 2 equals 16
9 times 2 equals 18
10 times 2 equals 20
11 times 2 equals 22
12 times 2 equals 24
- The combination of
while count < 13andcount = count + 1means that after \(12\) loop iterations the loop condition evaluatesFalseand the loop ends
Code Analysis: CounterIntelligence
- Consider the previous example and answer the following questions
- What statement would you change if you wanted to generate the times table for three instead of two?
- We would change
times_value
- We would change
- Which statement would you change if you wanted to generate up to the \(24\) times table?
- We would change the loop condition to
count < 25
- We would change the loop condition to
- What would happen to the program if we changed the line
count = count + 1tocount = count - 1- The loop would produce negative times tables, and never stop since
countwill be decreased every iteration and thus is always less than \(13\)
- The loop would produce negative times tables, and never stop since
Make Something Happen: Allow the User to Select the Times Value
Write a version of the previous example that asks the user for the value of the times table they want. Add validation so that the user must enter a number between \(2\) and \(12\) inclusive
Our solution (given in UserSelectedTimesTableTutor.py) prompts the user to enter a number between \(2\) - \(12\) inclusive, and then validates that the input is in the range.
A try, except block is used to catch any invalid input type, and the whole thing is wrapped in a while True block that only ends once a valid integer in the range \(2\) - \(12\) is received through the use of a break statement. - The actual times tables code is then identical
# Exercise 6.5 User SelectedTimes Tables Tutor
#
# Version of the times table tutor that allows the user to select the
# times table in the range 2 - 12 they are interested in
count = 1
while True:
try:
times_value_text = input(
"Please enter a times table between 2-12 (inclusive): "
)
times_value = int(times_value_text)
if times_value < 2 or times_value > 12:
print("Sorry, that is not between 2-12 (inclusive)")
else:
break
except ValueError:
print("Please enter an integer")
while count < 13:
result = count * times_value
print(count, "times", times_value, "equals", result)
count = count + 1The for Loop Construction
Forloops operate similar towhileloops, but are designed for when the number of iterations are known
block-beta
columns 6
space
space
title["Breakdown of a For"]:2
space
space
block:Input
columns 1
while["for"]
whileDescr["(start of the for construction)"]
end
block:MiddleOne
columns 1
condition["variable"]
conditionName["function name"]
conditionDescr["(variable controlled in the for)"]
end
block:In
columns 1
in["in"]
end
block:Items
columns 1
items["items"]
itemsDescr["(items to work through)"]
end
block:MiddleTwo
columns 1
colon[":"]
colonDescr["Colon"]
end
block:Suite
columns 1
suite["Statement block"]
suiteDescr["(statements)"]
end
classDef BG stroke:transparent, fill:transparent
class title BG
class condition BG
class conditionName BG
class conditionDescr BG
class colon BG
class colonDescr BG
class while BG
class whileDescr BG
class items BG
class itemsDescr BG
class suite BG
class suiteDescr BG
class in BG
forloops over a collection of items, acting on each item in turn- Each iteration acts on next item in the collection
- An example of a collection is a tuple, e.g.
names = ('Rob', 'Mary', 'David', 'Jenny', 'Chris', 'Imogen')namesis a tuple (denoted by the()containing the above names)- We’ll discuss Tuples in more detail in Chapter 8
- We can pair the above tuple with a
forloop e.g.
# Example 6.10 Name Printer
#
# Prints a collection of names
names = ("Rob", "Mary", "David", "Jenny", "Chris", "Imogen")
for name in names:
print(name)Rob
Mary
David
Jenny
Chris
Imogen
rangeis a python function for generating a collection of numbers- syntax is
range(start, stop)wherestartis included, butstopis excluded - e.g. We could rewrite ours times table program as using range (see [RangeBasedTimeTables.py])
- syntax is
# Example 6.11 Range Based Times Tables
#
# Demonstrates Python's range function using a for
# loop to generate a times table
times_value = 2
for count in range(1, 13):
result = count * times_value
print(count, "times", times_value, "equals", result)1 times 2 equals 2
2 times 2 equals 4
3 times 2 equals 6
4 times 2 equals 8
5 times 2 equals 10
6 times 2 equals 12
7 times 2 equals 14
8 times 2 equals 16
9 times 2 equals 18
10 times 2 equals 20
11 times 2 equals 22
12 times 2 equals 24
breakandcontinuealso work withforloopscontinuecauses the loop to proceed to the next item in the collection
Code Analysis: Loops, break and continue
Look at the following simple programs, and answer the corresponding questions about break and continue
What would the following code print?
for count in range(1, 13): if count == 5: break print(count) print('Finished')1 2 3 4 Finished- It would print
1,2,3,4then"finished" - Since when
countis \(5\) the loop breaks before the print statement and then the print outside the loop is called
- It would print
What would the following code print?
for count in range(1, 13): if count == 5: continue print(count) print('Finished')1 2 3 4 6 7 8 9 10 11 12 Finished- This program is similar to the above, except it would print
1through to12but skip5, before printing"Finished". - This is because the
continuecauses the loop iteration forcount = 5to skip the print statement in the loop and go to the next loop iteration
- This program is similar to the above, except it would print
What would the following code print?
for count in range(1, 13): count = 13 print(count) print('Finished')13 13 13 13 13 13 13 13 13 13 13 13 Finished- This will print \(13\) twelve times, because each time
countstarts a loop iteration it is set to the next value in therange(1, 13)- Then inside the loop
countis set to13and that value is printed
- Then inside the loop
- Of course
"Finished"is printed after the loop is down
- This will print \(13\) twelve times, because each time
Would the following program run forever?
while True: break print('Finished')Finished- No, it will immediately end because
breakexits the loop
- No, it will immediately end because
Would the following program print the message “Looping”?
while True: continue print('Looping')- No, the loop will hit the
continuekeyword and the go back to the start - This happens forever
- No, the loop will hit the
What would the following program do? Is it legal?
for letter in 'hello world': print(letter)h e l l o w o r l d- Strings are collections of letters
- The above program works, it loops over and prints each letter in the string
Make Something Happen: Make a Times Table Quiz
Reverse the behaviour of the times-table program so that rather than printing out the times-table your program instead asks questions like, “What is \(6\) times \(4\)?” The user could enter their answer, and the program could compare it with the correct answer and keep score of how many correct answers are given. You could use a loop to make the program produce \(12\) “times-table” questions, and you could use random numbers so that the quiz is different every time
Our solution given in TimesTableQuiz.py is relatively complete. We use first print a header message, then we set up a variable to track the number of correct answers total and a second variable to track the number of questions to ask. We then go into our for loop, looping over range(0, NumberOfQuestions), this makes the loop run NumberOfQuestions times.
The actual quiz then proceeds, we randomly generate the two numbers, the times_value from the range [2, 12] and the count from the range [1, 12]. We then calculate the correct answer, and prompt the user for an answer, using the standard ValueError exception handling. If the user’s answer is correct we congratulate them and increment the score, else we tell them what the correct answer is. After they’ve answered all the questions we give them the final score
# Exercise 6.6: Times Table Quiz
#
# Generates a times table quiz
import random
print("===Times table Quiz===")
score = 0
NumberOfQuestions = 12
for question in range(0, NumberOfQuestions):
times_value = random.randint(2, 12)
count = random.randint(1, 12)
correct_answer = times_value * count
while True:
try:
answer_text = input(
"What is " + str(count) + " x " + str(times_value) + ": "
)
answer = int(answer_text)
break
except ValueError:
print("Please enter an integer")
if answer == correct_answer:
score = score + 1
print("Correct!")
else:
print("Sorry that's wrong!")
print("The correct answer is", correct_answer, "you gave", answer)
print("You got", score, "/", NumberOfQuestions, "correct")Make a Digital Clock using Snaps
- Putting together what we’ve covered, we can make a digital clock using
snaps(see DigitalClock.py)
# Example 6.12: Digital Clock
#
# Uses a combination of loops and snaps to create a digital clock
import time
import snaps
while True:
current_time = time.localtime()
hour_string = str(current_time.tm_hour)
minute_string = str(current_time.tm_min)
second_string = str(current_time.tm_sec)
time_string = hour_string + ":" + minute_string + ":" + second_string
snaps.display_message(time_string)
time.sleep(1)Make Something Happen: Digital Alarm Clock
Combine the digital clock display from the previous example with the alarm clock from Chapter 5. Make the background image depend on the time of day
Our final program is a bit complicated so we’ll analyse it in parts. The full file can be read in DigitalAlarmClock.py
We start by extracting the relevant date and time information from the current time, and perform a boolean check if it’s a weekend.
We first then check if the time is night (defined heuristically as from \(7\) pm through to \(6\) am) or day (\(6\) am to \(7\) pm). We then display a moon as the background in the former case, or a sun in the later.
Remember we have to display the image first so that we can overlay the text on top.
# Exercise 6.7: Digital Alarm Clock
#
# Integrates the Alarm Clock Functionality of
# Chapter 5, with the Digital Clock Display of Chapter 6
import time
import snaps
while True:
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_min
second = current_time.tm_sec
day = current_time.tm_mday
month = current_time.tm_mon
year = current_time.tm_year
is_weekend = current_time.tm_wday >= 5
# draw the background
# define day as 6am - 7pm
if hour >= 6 and hour <= 19:
snaps.display_image("sun.png")
else:
snaps.display_image("moon.png")Now we prepare our datetime strings
# set up normal time and day clock behaviour
date_message = "The date is " + str(day) + "/" + str(month) + "/" + str(year)
time_message = "The time is " + str(hour) + ":" + str(minute) + ":" + str(second)
message = date_message + "\n" + time_messageNext we want to play a wake alarm at \(7:30\) giving as extra hour to sleep in on weekends. We also want to define a bed time. When the time hits \(7:30\) we want to play the alarm, then before bed time (\(22:00\))the clock should display a message telling us to get up, while after bed time it should tell us to go to sleep.
The if...else construct here is a bit more complicated. We only want to play the alarm sound at \(7:30:00\) rather than just if the user runs the clock after the wake up time. This is because the clock will then continuously play the sound every second it updates!
Our first if statement thus checks if we are exactly on the alarm time, and if we are plays the alarm sound and updates the message
We then have to consider now when we check if the time is after the alarm has gone off that it is also not before it is time to go back to bed. It’s cleaner to split this into two cases (our elif statements)
In the first case if the hour is equal to the hour to get up and greater than the minute to get up then it must be time to get up and we don’t need to play the alarm (since the first if statement catches this case). Note this makes the assumption that we don’t wake up at a time like \(8:30\) and then go to bed at \(8:59\) which is reasonable.
The second case is when the hour is greater than the hour to get up. Here we have to check that either the hour is less than the hour we go to bed at or if it is the same, that the minutes are less than the minutes we go to bed at. (Effectively the reverse of our old alarm condition.) In either of the previous cases we only then need to update the final printed message with the statement that we should be up
The last case (the else) is our default case for when none of the previous cases are matched. By exhaustion of cases this has to be when it is time for us to be in bed by default. So we don’t need to do extra checks and can just update the message to tell us to go to sleep
# Play alarm and optionally append a wake up message
hour_to_get_up = 7 + is_weekend
hour_to_sleep = 22
minute_to_get_up = 30
minute_to_sleep = 0
wake_up_message = "TIME TO GET UP!"
sleep_message = "TIME FOR BED!"
# case 1: On the alarm
if hour == hour_to_get_up and minute == minute_to_get_up and second == 0:
snaps.play_sound("siren.wav")
message = message + "\n" + wake_up_message
# Past the alarm
elif hour == hour_to_get_up and minute >= minute_to_get_up:
message = message + "\n" + wake_up_message
# past the alarm but before bed
elif hour > hour_to_get_up and (
hour < hour_to_sleep or (hour == hour_to_sleep and minute < minute_to_sleep)
):
message = message + "\n" + wake_up_message
# time for bed
else:
message = message + "\n" + sleep_messageFinally we display the message and then sleep for a second before updating the clock again
# display the message and then sleep
snaps.display_message(message, size=100)
time.sleep(1)Summary
whilerepeats statements as long as a logical expression isTrue- a
while Trueloop runs forever
- a
foris designed for looping through items in a collection of values one-by-onebreakandcontinueare two methods for controlling loop execution inside a loopbreakimmediately terminates a loopcontinueimmediately moves to the next loop iteration
- Tuples are a basic form of container for storing values
- declared as a comma separated list of values surrounded by parentheses
range(start, stop)creates a collection of integers fromstart(inclusive) tostop(exclusive)
Questions and Answers
- Do we really need loops?
- In theory no, you could unroll a loop into repeated code, however this can be clunky to do for arbitrary length loops or complicated control expressions
- Are loops dangerous?
- They can be. A poorly phrased loop may never execute, or potentially never stop executing.
- Some safety-critical applications may opt to exclude loops entirely to avoid these risks