COMP1701-004
fall 2023
lec-12
Hump Day!
Here Comes November








RECALL
Tracing code involving decisions adds a new level of fun to the proceedings.
Let's do 2 examples.
RECALL
def bladder_discomfort(trip_len):
level = ""
if trip_len > 4:
level = "mild"
elif trip_len > 7:
level = "painful"
elif trip_len > 10:
level = "critical"
else:
level = "normal"
return levelWhat does bladder_discomfort(11) return?
trace #1
RECALL
snoo = "woo"
b = 10
zob = ""
if (len(snoo) > b or len(zob) > 0):
zob = snoo
snoo = snoo.upper()
else:
b = snoo.upper()
snoo = zob + str(b)
print(snoo)
print(b)
print(zob)
if ("o" in snoo):
print(snoo.replace("o", "x"))
else:
print(snoo.replace("o", "u"))
What is displayed when this code is run?

trace #2
let's talk about these things today:
⦾ boolean-returning functions
⦾ branching boo-boo update
⦾ debugging
⦾ wishful coding
boolean-returning functions
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude and False otherwise.
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
Assumption!
lat_deg is an int guaranteed to be in -90 ... 90 - but no 0 allowed!
A northern latitude has a latitude > 0.
boolean-returning functions
def northern(lat_deg: int) -> bool:
return lat_deg > 0Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
....

🙋🏻♂️❓🙋🏻♀️Create a northern(lat_deg) function. It's got a one-line body.
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude and False otherwise.
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
Let's show some different ways of finishing the second part of our task.

First, though - you try!
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
def northern(lat_deg: int) -> bool:
return lat_deg > 0
def symbol_for(lat_deg: int) -> str:
if northern(lat_deg):
return "N"
else:
return "S"
Easy to follow.
Is the else necessary?
Variant 1: if/else with returns in each
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
def northern(lat_deg: int) -> bool:
return lat_deg > 0
def symbol_for(lat_deg: int) -> str:
if northern(lat_deg):
return "N"
return "S"
when you return, you leave the function!
Variant 2: if with return, no else
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
def northern(lat_deg: int) -> bool:
return lat_deg > 0
def symbol_for(lat_deg: int) -> str:
symbol = ""
if northern(lat_deg):
symbol = "N"
else:
symbol = "S"
return symbol
Assign a variable a temporary dummy value, then re-assign in each branch.
Finally, return the variable.
Variant 3: if/else with standard single return
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
def northern(lat_deg: int) -> bool:
return lat_deg > 0
def symbol_for(lat_deg: int) -> str:
if northern(lat_deg):
symbol = "N"
else:
symbol = "S"
return symbol
Variant 4: if/else with Python-only single return
Assign value to a variable each branch.
Finally, return the variable.
Won't work in C++ or Java!
JP! Run this in PythonTutor to illustrate!
boolean-returning functions
Task
Make a function northern(lat_deg) that returns True if lat_deg is a northern latitude (and False otherwise).
Then use that function in another function symbol_for(lat_deg), that returns "N" if lat_deg is a northern latitude, and "S" otherwise.
def northern(lat_deg: int) -> bool:
return lat_deg > 0
def symbol_for(lat_deg: int) -> str:
symbol = "S"
if northern(lat_deg):
symbol = "N"
return symbol
Variant 5: if/else single return w/ default var value
Choose a default value for a shared variable. Re-assign to that variable if necessary.
Finally, return that variable.
boolean-returning functions
So which way is best?
Follow whoever is paying you.
branching boo-boos
REVISITED
Need to add one - and clarify another.
if lives_left > 0:
print("Continue?")
else lives_left <= 0:
print("Game over!")boo-boo #2
Review
Bad Syntax
🙋🏻♂️❓🙋🏻♀️What's the problem? How do we correct it?
Review
tank_empty = True
if tank_empty == True:
print("The tank...she be empty!")
else:
print("We got gas - let's roll!")boo-boo #1
if 1 <= dial <= 10:
print("The dial is pleased.")
boo-boo #3
if amount < 0:
print("Invalid amount.")
elif amount >= 0 and amount < 40:
print("Add some stuffs.")
else:
print("Yay! Free stuffs.")boo-boo #5
Bad Practices
if user_choice == "black" or "white":
print("Your world is very...plain.")boo-boo #4
we need to talk 'bout this
BTW - you don't have to memorize the numbers...they're just an arbitrary thing I made up!
if 1 <= dial <= 10:
print("The dial is pleased.")
Mmmmm...humble pie.
This is called a chained comparison.
Most languages - particularly the ones you'll encounter for the rest of your degree - don't allow this sort of thing.
But Python does.
I did not know this until I started looking through your labs this weekend!

That being said, I'd be wary of getting too comfortable using it.
if a != b != c:
# do something
Not only will you NOT be able to use it in your future classes, but it has a few teeth. For example:
Do you think this means "do something if a, b, and c are all different"?
What if a and c are 3, but b is 1?
A noo boo-boo.
def discount(num_items: int) -> float:
'''Return discount depending on number of items purchased.'''
if num_items <= 1:
return 0
elif num_items <= 3:
return 0.1
elif num_items >3:
return 0.2
boo-boo #6

Why is our editor griping?
🙋🏻♂️❓🙋🏻♀️How do we correct this?


debugging
debugging
A (software) bug is an error in source code that causes that code to not do what it's supposed to do.
Debugging is the act of finding and removing bugs.
debugging - types of bugs
We can group bugs into 3 broad categories:
- syntax errors
- runtime errors
- logic errors
debugging - types of bugs
syntax errors
What's wrong?
The code violates one or more syntax rules and so the poor interpreter can't even run the code, because it can't interpret it.
How do I know I have one?
Oh, don't worry - your coding tools will let you know,

How should I feel when I see one?
Joyous, with perhaps a hint of embarrassment.
debugging - types of bugs
syntax errors - examples
import sin from math
def skill_level(player: string) -> int
result = -1
very skilled = False or player == 'krom"
if len(player) =< 3:
result = 2
return result / sin result
def main:
skill_level("Mr. Tibbs")
main()Taste the rainbow!
How many can you find?
pro tip
if you can't find the error on the line being reported, look UP one line!
debugging - types of bugs

runtime errors
What's wrong?
The code, while syntactically correct, attempts to do something that will go when the code is run.
How do I know I have one?
Your terminal will vomit forth a traceback and a pall will settle upon you.
How should I feel when I see one?
Slightly confused until you read the traceback...after which, irritated.
debugging - types of bugs

runtime errors - example 1
def ask_for_skill_level() -> int:
return input("What's your skill level (1-10)? ")
def main():
skill_level = ask_for_skill_level()
if skill_level > 3:
print("Wow, you have mad skillz!")
else:
print("You are not worthy of my time.")
main()
What will happen no matter what the user enters?

Do NOT neglect the clues!
debugging - types of bugs
runtime errors - example 2
def ask_for_num_guests() -> int:
return int(input("How many guests? "))
def ask_for_num_spiders() -> int:
return int(input("How many spiders? "))
def main():
num_guests = ask_for_num_guests()
num_spiders = ask_for_num_spiders()
num_spiders_per_guest = num_guests // num_spiders
print(f"Each guest should get {num_spiders_per_guest} spiders.")
main()debugging - types of bugs
What will happen if the user enters 0 for the number of spiders?
What will happen if the user enters "none" for the number of guests OR spiders?
logic errors
What's wrong?
The code is syntactically correct and runs without blowing up...but that thing it's supposed to do? Nope - it don't do that.
How do I know I have one?
When you run the code, something seems...off. Either a lot, or more terrifyingly, just a smidge.
How should I feel when I see one?
Dread, followed by an odd mix of despondency and grim determination.
debugging - types of bugs
logic errors - example 1
debugging - types of bugs
MM_PER_CM = 100
def get_side_len_cm():
len_as_text = input("Length of side in cm? ")
return float(len_as_text)
def squarea(side_len):
return side_len ** 2
def display_result(side_len, area):
print(f"A {side_len}cm x {side_len}cm square has area {area:.1f}mm^2")
def main():
side_len_cm = get_side_len_cm()
side_len_mm = side_len_cm * MM_PER_CM
area = squarea(side_len_mm)
display_result(side_len_cm, area)
main()oops
logic errors - example 2
debugging - types of bugs
dd
def extra_cashiers_avail(num_cashiers):
return num_cashiers > 1
def lines_are_too_long(len_longest_line):
return len_longest_line > 5
def is_weekend(day_of_week):
return day_of_week == "sa" or day_of_week == "su"
def should_open_checkout(dow, num_cashiers, len_longest_line):
return is_weekend(dow) and \
extra_cashiers_avail(num_cashiers) and \
lines_are_too_long(len_longest_line)
def main():
dow = "su"
longest_line = 7
num_cashiers = 4
if should_open_checkout(dow, longest_line, num_cashiers):
print("open another checkout")
main()
oops
logic errors - example 3
debugging - types of bugs
- return "critical" if the length of the trip is 10 or more,
- return "painful" if the length is more than 7 but less than 10,
- return "mild" if the length is more than 4 but less than or equal to 7,
- return "normal" otherwise
def bladder_discomfort(trip_len):
level = ""
if trip_len > 4:
level = "mild"
elif trip_len > 7:
level = "painful"
elif trip_len > 10:
level = "critical"
else:
level = "normal"
return levelDesired behaviour of function:
debugging -
strategies
debugging strategies
You're going to encounter a lot of bugs in this field.

Welcome to your life.
debugging - types of bugs
you're going to screw up.
A lot.
For as long as you live.
It's ok -
Whatever.
- Listen to your development tools - but don't listen blindly
- Rubber-duck debug
- Get into a debugger's mindset: your view of reality is wrong. Accept it.
- Start at the scene of the crime and work backwards
- Find - and record - inputs AND expected outputs for each function
- Find - and record - poisonous inputs that break your functions
- Avoid typing things in manually during debugging; call broken functions with poisonous inputs (see #6)
- see what your code is actually doing by tracing it with poisonous inputs
- manually
- with print statements (aka trace statements)
- with a debugger - but don't step over until you predict what should happen
Here is a laundry list of general strategies you can use to help you squash them bugs!


wishful coding
wishful coding & helper functions
Let's make a tiny app.
It's for a tiny plane with a forgetful pilot.
It asks how much fuel there is and whether the door is closed.
If there is 100L or more of fuel and the door is closed, it displays Ready for takeoff!; otherwise, it shows Don't take off yet, ya goof!
wishful coding & helper functions
We'll use something called wishful coding (among other things)
This technique is quite fun to use. It doesn't work for every problem - but it works for a lot of them.
wishful coding & helper functions
def main() -> None:
pass
main()
Let's start building the main() habit.
Just having a bunch of code in your source file creates a whole bunch of global variables. This ain't good news. (Google "global variables are evil" if you're skeptical!)
pass is a useful bugger - it doesn't do anything...except not blow up
wishful coding & helper functions
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
main()
Next, we'll write the code we wished was there
It should read like English...and solve the problem.
These are helper functions - functions we create to give a name to a part of our algorithm. We should use them - a LOT.
wishful coding & helper functions
Next, we'll shut up our editor's whining by making stubs - functions that don't actually do anything useful (yet)
def ask_for_fuel_level() -> int:
return -1
def ask_if_door_closed() -> bool:
return False
def plane_ready_for_takeoff(fuel_level, door_closed) -> bool:
return False
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
main()
stubs!
wishful coding & helper functions
Now, make those helper functions actually do what you want! (1/3)
def ask_for_fuel_level() -> int:
return int(input("How much fuel do you have? "))
def ask_if_door_closed() -> bool:
return False
def plane_ready_for_takeoff(fuel_level, door_closed) -> bool:
return False
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
fuel = ask_for_fuel_level()
print(fuel)
test that function - just a bit!
wishful coding & helper functions
Now, make those helper functions actually do what you want! (2/3)
def ask_for_fuel_level() -> int:
return int(input("How much fuel do you have? "))
def ask_if_door_closed() -> bool:
response = input("Is the door closed (yes/no)? ")
return response == "yes"
def plane_ready_for_takeoff(fuel_level, door_closed) -> bool:
return False
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
door_closed = ask_if_door_closed()
print (door_closed)
test that function!
wishful coding & helper functions
Now, make those helper functions actually do what you want! (3/3)
def ask_for_fuel_level() -> int:
return int(input("How much fuel do you have? "))
def ask_if_door_closed() -> bool:
response = input("Is the door closed (yes/no)? ")
return response == "yes"
def plane_ready_for_takeoff(fuel_level, door_closed) -> bool:
SAFE_THRESHOLD = 100
return door_closed and fuel_level >= SAFE_THRESHOLD
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
plane_ready_for_takeoff(99, True)
plane_ready_for_takeoff(100, False)test that function!
door_closed: T/F
fuel level boundaries: 99, 100, 101
try:
- T/99, T/100, T/101
- F/99, F/100, F/101
wishful coding & helper functions
All done - now test the whole thing.
def ask_for_fuel_level() -> int:
return int(input("How much fuel do you have? "))
def ask_if_door_closed() -> bool:
response = input("Is the door closed (yes/no)? ")
return response == "yes"
def plane_ready_for_takeoff(fuel_level, door_closed) -> bool:
SAFE_THRESHOLD = 100
return door_closed and fuel_level >= SAFE_THRESHOLD
def main() -> None:
fuel_level = ask_for_fuel_level()
door_closed = ask_if_door_closed()
if plane_ready_for_takeoff(fuel_level, door_closed):
print("Ready for takeoff!")
else:
print("Don't take off yet, ya goof!")
main()
lec-12
By Jordan Pratt
lec-12
branching boo-boos update | boolean-returning functions | debugging | wishful coding
- 222