it_is_time_to_get_up = True
print(it_is_time_to_get_up)True
A number of the code examples in this use the file siren.wav, this can be found in the corresponding chapter in the samples submodule. For space reasons we haven’t uploaded it to the github
int to count the number of hairs on a person’s head, but a bool to indicate if they are baldTrue or False
false,True and False are python keywords, and are case-sensitive, e.g. true and false will not work as expectedOpen up the python interpreter and work through the following questions to understand booleans
What do you think would happen if you printed the contents of a boolean value?
True or FalseWhat do you think would happen if you gave the word True to the input function?
x = input("True or False: ")
True or False: True
input returns it’s input as a string, so in this case x will not be a bool but rather a string with the value "True"Is there a python function called bool that will convert things into Boolean, just like there are int and float functions?
True
False
False
True
False
True
True while zero, evaluates as False Similarly the empty string evaluates False while a non-empty string evaluates as TrueWhat happens if a program combines bool values with other values?
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[3], line 1 ----> 1 'Hello' + True TypeError: can only concatenate str (not "bool") to str
True is implicitly converted to the integer value \(1\)False is implicitly converted to the integer value \(0\)True or False explicitly but instead as the result of evaluating an expression
True or False which naturally suits being stored in a booleanWe can get the time through the time library we’ve seen before
time.localtime returns an object containing information about the current time.
localtime| Attribute | Value |
|---|---|
| tm_year | Year (for example, 2017) |
| tm_mon | Month (in the range 1 … 12, 1 represents January) |
| tm_mday | Day in the Month (in the range 1 … month length) |
| tm_hour | Hour in the Day (in the range 0 … 23) |
| tm_min | Minute in the Hour ( in the range 0 … 59) |
| tm_sec | Seconds in the Minute ( in the range 0 … 59) |
| tm_wday | Day of the Week (in the range 0 … 6 with Monday as 0) |
| tm_yday | Day in the Year (in the range 0 … 364 or 365 depending on if the year is a leap year) |
localtime object might look like,| Attribute | Value |
|---|---|
| tm_year | 2017 |
| tm_mon | 7 |
| tm_mday | 19 |
| tm_hour | 11 |
| tm_min | 40 |
| tm_sec | 30 |
| tm_wday | 2 |
| tm_yday | 200 |
Lets make a clock that displays only the hour value, using localtime. These one-handed clocks are supposed promote a more relaxed attitude. Create a new program (OneHandedClock.py) and copy the below text.
The hour is 6
Run the program, it should print out the current hour
Improve the previous example to produce a more fully featured clock that reports the time, and date when run
We can use the table above to grab the correct attributes. We then simply need to format the attribute as necessary. The final program is given below
# Exercise 5.1: Improved Clock
#
# An improved clock that displays the date and time when run
import time
current_datetime = time.localtime()
day = current_datetime.tm_mday
month = current_datetime.tm_mon
year = current_datetime.tm_year
print("The date is", day, "/", month, "/", year)
seconds = current_datetime.tm_sec
minutes = current_datetime.tm_min
hours = current_datetime.tm_hour
print("The time is", hours, ":", minutes, ":", seconds)The date is 13 / 3 / 2026
The time is 6 : 24 : 49
True or False, e.g.block-beta
columns 3
space
title["Breakdown of an Example Comparison Expression"]
space
block:Input
columns 1
operand1["hour"]
operand1Word["Operand"]
operand1descr["(thing to work on)"]
end
block:Middle
columns 1
operator[">"]
operatorWord["Operator"]
operatorDescr["(thing to do)"]
end
block:Output
columns 1
operand2["6"]
operand2Word["Operand"]
operand2descr["(thing to work on)"]
end
classDef BG stroke:transparent, fill:transparent
class title BG
class operand2Word BG
class operand2descr BG
class operand1Word BG
class operand1descr BG
class operatorWord BG
class operatorDescr BG
| Operator | Name | Effect |
|---|---|---|
| \(>\) | Greater than | True if the left argument is greater than the right, else False |
| \(<\) | Less than | True if the left argument less than the right, else False |
| \(>=\) | Greater than or Equal | As for Greater than but also True if the left argument equals the right |
| \(<=\) | Less than or Equal | As for Less than but also True if the left argument equals the right |
| \(==\) | Equals | True if the left argument equals the right argument, else False |
| \(!=\) | Not Equals | True if the left argument does not equal the right argument, else False |
it_is_time_to_get_up to True if the variable hour is greater than \(6\) else sets it to FalseUse the python interpreter to work through the following questions in order to understand Comparison Operators
How does the equality operator work?
True if the two operands hold the same valueHow do I remember which relational operator to use?
Can we apply relational operators between other types of expressions?
Yes. For example, the \(>\) and \(<\) operators when used to compare strings will use an alphabetic ordering, e.g.
Equality and Floating-point Values
In Chapter 4 we noted that floating points only approximate a specific real-value. These approximations can cause issues when using comparison operators, e.g.
x and y should both notionally store \(0.3\), but the equality shows they are unequal. This is because the addition of \(0.1\) and \(0.2\) actually leads to y storing the slightly inaccurate \(0.3000...4\)type function, type(x) returns the type of the variable x, especially useful for investigating the type of values returned by library functions you’ve never seen beforeUse the python interpreter to answer the following questions and investigate boolean operators
What does the following expression evaluate too?
not inverts the value of a boolean, so True is converted to FalseHow about this expression?
and is True iff both arguments are True as is the case above, so the result is TrueHow about this expression?
False and will evaluate to FalseHow about this expression?
True or will evaluate to TrueSo far, the examples have only used boolean values. What happens if we mix boolean and numeric values?
and to return True. However ,instead \(1\) is returned. This is due to some odd python behaviour
Python sees True \(\rightarrow\) result of and implied by second argument
If we flip the arguments, we should see this more clearly
TrueThe same behaviour will also occur with or
or operator short-circuits on \(1\), so returns \(1\)or evaluates the first argument as false, so cannot short-circuit, the second argument is returned, i.e Trueand to try construct an expression that will correctly evaluate when the time is after \(7:30\), naively we might expect,| Hour | Minute | Desired | Output |
|---|---|---|---|
| 6 | 0 | False | False |
| 7 | 29 | False | False |
| 7 | 30 | True | True |
| 8 | 0 | True | False |
hour > 7 is true, but minute > 29 is false, so we need to be more precise,Be Careful with Logic Operations
When working with boolean operations you should always check that the logic matches what you expect!
if Constructif a boolean condition is met
if operator# Example 5.2: Simple Alarm Clock
#
# Demonstrates `if` using a simple alarm clock
import time
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_sec
it_is_time_to_get_up = (hour > 7) or (hour == 7 and minute > 29)
if it_is_time_to_get_up:
print("IT IS TIME TO GET UP")IT IS TIME TO GET UP only if the time is after \(7:30\)if construct starts with the word if, following by a boolean value called the condition, then a :if is True are then written below the if and indented one levelif is executedTrue the indented branch is runFalse the indented branch is skippedif rather than an intermediate variableif statementLet us improve the previous example to also play a sound if it’s time to get up. Create a program (SirenAlarmClock.py) with the contents below
# Example 5.3: Siren Alarm Clock
#
# Improves the Simple Alarm Clock to also play a sound
import time
import snaps
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_min
if (hour > 7) or (hour == 7 and minute > 29):
snaps.display_message("TIME TO GET UP")
snaps.play_sound("siren.wav")
# pause the program to give time for the sound to play
time.sleep(10)This program now runs three statements in the if
if condition, we write it either before or after the if statementAdd to the simple Alarm Clock, by making it so the program will always print the current time regardless of if the alarm goes off. Create a new program (AlarmClockWithTimeDisplay.py). Enter the following contents,
# Example 5.4: Alarm Clock with Time Display
#
# A variant of Alarm Clock to also always display the time
import time
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_min
if (hour > 7) or (hour == 7 and minute > 29):
print("TIME TO GET UP")
print("RISE AND SHINE")
print("THE EARLY BIRD GETS THE WORM")
print("The time is", hour, ":", minute)The time is 6 : 24
Indented Text can cause Big Problems
As seen above, python uses indentation for control flow, this has the advantage in that it follows normal code style practices, but has some pitfalls
If the indention is wrong the program won’t run
i.e. if one line is indented four spaces, and the next three an error will be thrown
Cell In[24], line 8 print("The early bird gets the worm...") ^ IndentationError: unexpected indent
A more insidious error, occurs if one mixes tabs and spaces in the indentation, since the code may appear to be fine until it attempts to run
if Statementif has a structure likeblock-beta
columns 4
space
title["Breakdown of an if statement"]:2
space
block:Input
columns 1
if["if"]
ifDescr["(start of the if construction)"]
end
block:Condition
columns 1
condition["condition"]
conditionDescr["(value that is true or false)"]
end
block:Colon
columns 1
colon[":"]
colonDescr["colon"]
end
block:Suite
columns 1
suite["suite"]
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 suite BG
class suiteDescr BG
class if BG
class ifDescr BG
A set of indented statements on the lines proceeding the if
A set of statements on the same line as the if each seperated by a semicolon (;) e.g.
You can’t combine inline if statements, with indented if statements, e.g.
Cell In[26], line 7 print("The early bird gets the worm...") ^ IndentationError: unexpected indent
Use the python interpreter to answer the following questions to understand conditional statements
Can we work with conditional statements using the python shell?
The shell may display ... instead of >>> or, omit >>> and indent
Once done writing the if statement, simply deindent
Try write the following in the shell, and verify the output
How many spaces must you indent a suite of Python statements controlled by an if statement?
else to an if ConstructionTrue and False brancheselse is a keyword that lets us add behaviour that executes when an if evaluates as FalseModify the Simple Alarm Clock to now print a message telling us to go back to bed if it before our alarm should go off. Write a new program (SimpleAlarmClockWithElse.py) with the following contents,
# Example 5.5: Simple Alarm Clock
#
# Variant of the Simple Alarm Clock
# that modifies the output depending on if its time to get up
import time
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_min
if (hour > 7) or (hour == 7 and minute > 29):
print("IT IS TIME TO GET UP")
else:
print("Go back to bed")Go back to bed
if-else statements is printedWork through the following questions to understand if constructions
Must an if construction have an else part?
if that we could exclude the else in that case no additional code runs if the if evaluates FalseWhat happens if a condition is never True?
if statement can be used to compare strings, as seen with the comparison operatorsThe following program uses the equality operator and an if statement to greet a person if their name matches. What is a potential issue with this program?
"Rob" exactly"ROB", or "rob" or some variation thereof, the statement will not match.We can fix this by using the string method upper, this converts all forms of the word "rob" to "ROB" which we can reliably check against. The new program looks like
lower to compare against an all lowercase wordConsider the following questions to learn about methods and functions
How do lower() and upper() work?
Why do we have to write lower() and not lower?
Leave the parentheses off, and see what happens
We are instead returned a description of the method itself
What’s the difference between functions and methods?
if ConditionsLet us demonstrate nested if through a greeter which requires a follow on code word to confirm the identity of the user. Create a program (CodedGreeter.py) with the following contents
"rob" the second prompt never occurs and the program ends.# Example 5.9: Coded Greeter with Outer Else
#
# Asks the user for a follow on code to confirm their ID
# before the program greets them
# Has an additional outer else clause for the case that the nested
# if does not run
name = input("Enter your name: ")
if name.upper() == "ROB":
code = input("Enter the codeword: ")
if code == "secret":
print("Hello, Oh great one")
else:
print("Begone. Imposter")
else:
print("You are not Rob. Shame.")else clause, attached to the first outer, if condition"ROB"Improve the Alarm Clock. Make the alarm display the date as well as the time, and let the user sleep in on the weekends.
Our implementation is given below,
# Exercise 4.2: Advanced Alarm Clock
#
# An Advanced Alarm Combining the Behaviour
# of most increments of the alarm clock
# and allowing you to sleep in on weekends
import time
import snaps
current_time = time.localtime()
hour = current_time.tm_hour
minute = current_time.tm_min
day = current_time.tm_mday
month = current_time.tm_mon
is_weekend = current_time.tm_wday >= 5
date_message = "The date is " + str(day) + "/" + str(month)
time_message = "The time is " + str(hour) + ":" + str(minute)
msg = ""
up_hour = 7 + is_weekend # get to sleep in an extra hour on weekends
if (hour > up_hour) or (hour == up_hour and minute > 29):
msg = msg + "TIME TO GET UP"
snaps.play_sound("siren.wav")
else:
msg = msg + "Go back to bed!"
msg = msg + "\n" + date_message + "\n" + time_message
snaps.display_message(msg, size=50)
time.sleep(10) # leave time for the sound and to readMost of the text simply exists to correctly create the final message we will display on the screen. The most important parts are, is_weekend = current_time.tm_wday >= 5 which uses the fact that Saturday and Sunday have the value \(5\) and \(6\) in the current_time.tm_wday attribute (A number representing the day in the week) to set a boolean flag. We then use the fact that True acts numerically as one, and False acts numerically as zero to let us sleep in an hour on the weekend using up_hour = 7 + is_weekend which is \(8\) on weekends and \(7\) on weekdays.
We then run through the code as we have for most of the alarm clock cases, using an else clause to ensure we always have a message for the user, and appending the date and time message to this output.
Lastly we pass the method to snaps for display
Scenario:
A local theme park wants you to write a program that will let users check if they meet the age requirements to go on a ride. They provide the following table covering the current rides
Ride Restrictions Scenic River Cruise None Carnival Carousel At least 3 years old Jungle Adventure Water Splash At least 6 years old Downhill Mountain Run At least 12 years old The Regurgitator At least 12 years old and less than 70
Welcome to our Theme Park
These are the available rides
1. Scenic River Cruise
2. Carnival Carousel
3. Jungle Adventure Water Splash
4. Downhill Mountain Run
5. The Regurgitator
Please enter the ride you want: 1
You have selected the Scenic River Cruise
There are no age limits for this ride
Design the User Interface with the Customer
The UI can be the most important and most difficult part of design because it can be very subjective. Ultimately the Customer is the one paying and so they should be involved in the UI design throughout!
# Example 5.10: Ride Selector Start
#
# The basic shell of the Ride Selector UI
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
""")
ride_number_text = input("Please enter the ride number you want: ")
ride_number = int(ride_number_text)
if ride_number == 1:
print("You have selected Scenic River Cruise")
print("There are no age limits for this ride")if statements.
if statements which
if ride_number == 2:
print("You have selected the Carnival Carousel")
if age >= 3:
print("You can go on the ride")
else:
print("Sorry, you are too young")
if ride_number == 3:
print("You have selected Jungle Adventure Water Splash")
if age >= 6:
print("You can go on the ride")
else:
print("Sorry, you are too young")Reduce duplicated Code
You may have noticed that the above statement appears to have a bunch of duplicated code. The rough structure is,
select ride
if age of user is greater than or equal to the rides min age
Inform the user they can go on the ride
else:
Inform the user they cannot go on the ride
Programmers typically don’t like to repeat themselves as it increases the number of ways a program can go wrong. So ideally we would like a way were we could write something like the above once and have the appropriate checks be carried out, and the message printed without having to write it out for every case. We’ll look at some ways to do this later in the book.
snapsget_string methodAs written, the snaps get_string method on my machine, did not work when running Pygame 2. I had to modify the method to the following,
def get_string(prompt, size=50, margin=20,
color=(255, 0, 0), horiz='left', vert='center',
max_line_length=20):
'''
Reads a string from the user
'''
setup()
result = ''
cursor_char = '*'
cursor = None
def redraw():
clear_display()
render_message(prompt+result, margin=margin, size=size,
horiz=horiz, vert=vert, color=color, cursor=cursor)
def cursor_flip():
nonlocal cursor
# create a timer for the cursor
cursor_event = pygame.USEREVENT+1
pygame.time.set_timer(cursor_event,500)
pygame.key.start_text_input()
while True:
event = pygame.event.wait()
if event.type == cursor_event:
if cursor:
cursor = None
else:
cursor = cursor_char
redraw()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
break
elif event.key == pygame.K_BACKSPACE:
if len(result) > 0:
result = result[:-1]
redraw()
elif event.type == pygame.TEXTINPUT:
if len(result) < max_line_length:
result += event.text
redraw()
# disable the timer for the cursor
pygame.time.set_timer(cursor_event,0)
return resultI won’t go into detail on explaining the changes since it’s above the level we’ve currently been discussing but if you have issues with the running any of the snaps get_string programs in this book, I would recommend trying the above replacement to the function
The below program is the outline for an implementation of the Ride Selector Program using snaps to provide a GUI
# Example 5.12: Theme Park Snaps Display
#
# Reimplments the shell of the Ride Selector Menu using Snaps
import time
import snaps
snaps.display_image("themepark.png")
prompt = """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
Select your ride: """
ride_number_text = snaps.get_string(prompt, vert="bottom", max_line_length=3)
confirm = "Ride " + ride_number_text
snaps.display_message(confirm)
time.sleep(5) #gives user time to read the outputUsing the previous example, complete the ride selector program. Extending its features where reasonable
We’ll reimplement all the features of the original text-based interface, but add in the siren sound effect if the user is unable to ride the ride. Otherwise this proceeds as with most of our conversions to snaps. We replace print with snaps.display_message and introduce some work to build the string that we want to send to snaps.display_message. In this case we create a string that is nicely formatted to output
Our final implementation can be found in the file ThemeParkSnapsDisplay.py, or read from down below, observe the usual use of the time.sleep function to prevent the window from immediately closing
# Exercise 5.3: Snaps Ride Selector
#
# Reimplments the entirety of the Theme Park Ride Selector using
# a snaps interface, and adds some audio ques to warn the user
# when they are ineligable for ride
import time
import snaps
snaps.display_image("themepark.png")
prompt = """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
Select your ride: """
ride_number_text = snaps.get_string(prompt, vert="bottom", max_line_length=3)
confirm = "Ride " + ride_number_text
snaps.display_message(confirm)
time.sleep(2) # gives user time to read the output
ride_number = int(ride_number_text)
if ride_number == 1:
msg = confirm + "\nScenic River Cruise\n\nThere are no age limits for this ride"
snaps.display_message(msg, size=100)
else: # need to get the age of the user
age_text = snaps.get_string(
"Please enter your age: ", vert="bottom", max_line_length=3
)
age = int(age_text)
if ride_number == 2:
msg = confirm + "\nCarnival Cruise"
if age >= 3:
msg = msg + "\n\nYou can go on the ride"
snaps.display_message(msg, size=100)
else:
snaps.play_sound("siren.wav")
msg = msg + "\n\nSorry, you are too young"
snaps.display_message(msg, size=100)
if ride_number == 3:
msg = confirm + "\nJungle Adventure Water Splash"
if age >= 6:
msg = msg + "\n\nYou can go on the ride"
snaps.display_message(msg, size=100)
else:
msg = msg + "\n\nSorry, you are too young"
snaps.play_sound("siren.wav")
snaps.display_message(msg, size=100)
if ride_number == 4:
msg = confirm + "\nDownhill Mountain Run"
if age >= 12:
msg = msg + "\n\nYou can go on the ride"
snaps.display_message(msg, size=100)
else:
msg = msg + "\n\nSorry, you are too young"
snaps.play_sound("siren.wav")
snaps.display_message(msg, size=100)
if ride_number == 5:
msg = confirm + "\nThe Regurgitator"
if age >= 12:
# first check age not too lowe
if age > 70:
# Age is too old
msg = msg + "\n\nSorry, you are too old"
snaps.play_sound("siren.wav")
snaps.display_message(msg, size=100)
else:
msg = msg + "\n\nYou can go on the ride"
snaps.display_message(msg, size=100)
else:
msg = msg + "\n\nSorry, you are too young"
snaps.display_message(msg, size=100)
time.sleep(5)Using snaps and the weather functions it includes, write a simple program to remind the user to wrap up warm, wear sunscreen etc.
We’ll use the basic outline of the solution in the book,
The first step is to convert the print statements to instead use the snaps, display_message function. This requires us to do the usual work of building the string before we display it. Next we also want to display an image, either a sun or a snowflake depending on if the weather is hot or cold. Since we’re grabbing some new images, we run into an issue that snaps doesn’t work to rescale the images out of the box. We can fix this by adding the line image = image.convert_alpha() before the image = pygame.transform.smoothscale(image, window_size) line in display_image in snaps. Our final program (Weather Helper) looks like,
# Exercise 5.4 Weather Helper
#
# Simple Weather Program that reminds the user about
# the weather conditions, with helpful text and
# pictures
import time
import snaps
temp = snaps.get_weather_temp(latitude=47.61, longitude=-122.33)
conditions = snaps.get_weather_desciption(latitude=47.61, longitude=-122.33)
if temp is None or conditions is None:
msg = "Could not retrieve Weather..."
else:
msg = "The temperature is: " + str(temp)
if temp < 40:
msg = msg + "\n\nWear a coat - it is cold out there"
snaps.display_image("snowflake.png")
elif temp > 70:
msg = msg + "\n\nRemember to wear sunscreen"
snaps.display_image("sun.png")
msg = msg + "\n\nThe weather is " + conditions
snaps.display_message(msg, size=100, color="red")
time.sleep(5)Ignore the line if temp is None or conditions is None, this is some error handling code we’ll look at in a latter chapter. Notice that since no matter which path we go through the if, elif chain we’ll post a message at the end. So we use the branch code in order to set up the appropriate message, while the call to display_message sits outside the loop, so we don’t have to call it on every path.
Using randint and if statements write a fortune teller program that gives random fortunes to the user
We’ll expand on the prototype given by providing two additional statements, one relating to the future and the other relating to the wealth. We’ll follow the structure of using random.randint(1, 6) to simulate rolling a six-sided die, but spice it up by using if-elif-else clauses to play with the relative weighting of different statements.
# Exercise 5.5 Fortune Teller Program
#
# A simple program that uses random numbers to generate a sequence of
# fortunes for the user
import random
# Meeting someone
if random.randint(1, 6) < 4:
print("You will meet a tall, dark stranger")
else:
print("Nobody unexpected will enter your life")
# Money
result = random.randint(1, 6)
if result == 1:
print("I see untold riches in your future")
elif result <= 3:
print("A life of comfort is coming")
elif result < 6:
print("You would do well to husband your wealth")
else:
print("I see a future lived on the streets...")
# Advice
result = random.randint(1, 6)
if result <= 2:
print("Sometimes the answers to our future, come from the past")
elif result < 6:
print("To define your future, avoid getting hung up on the past")
else:
print("You will soon face a decision that will redefine everything")Nobody unexpected will enter your life
I see a future lived on the streets...
You will soon face a decision that will redefine everything
We use a mix of ==, <= and < operators to emphasise the clarity of the branching. This implementation is quite simple (because the exercise does not personally interest me that much) Feel free to expand on my solution
True or Falseif is used to control program execution in response to boolean expressions
if executes code if a condition is Trueand, or and not are used to create new boolean expressions from existing ones
and is True if both expressions are True else Falseor is True if either expression is True else Falsenot flips the truth of a boolean expression
True \(\rightarrow\) FalseFalse \(\rightarrow\) Trueif conditions you can nest inside each other?
if statements. Most people will emphasise that if you’re finding that you’re needing to write heavily nested code (the exact number of what constitutes heavy is debated but \(3\) is a rough guide) you should look at if there’s a better way to write