COMP1701-004

fall 2023

lec-11

The Fooooture

Marc Schroeder is present in class today and is conducting observations as part of an approved research study. No audio or video recording is being conducted.

 

His fieldnotes may record general observations about the overall nature of classroom activities and discussions. However, these will not include personal or identifying details about individuals or their participation, except for those students who are participating in other aspects of the study.

 

If you have any questions or concerns, then please let me know, and I’ll direct you to the appropriate resource.

RECALL

SIZE = 9
WEIGHT = 2

CARTON_CAP = 3
COST_PER_EGG = 2.0

QUIT = "quit"

p1_score = 3
p2_score = 4

num_eggs = 7

response = "QUIT"
save_complete = False

What are the values and types of the following:

1. p1_score + p2_score
2. num_eggs * COST_PER_EGG
3. SIZE % WEIGHT
4. (p1_score + 1) > p2_score
5. QUIT == response or save_complete
6. len(QUIT) != int(COST_PER_EGG * 2)

let's talk about these  things today:

 branching

 if, if-else, if-elif-else statements

common branching boo-boos

 boolean-returning functions

What can a CPU do again?

  • read from an input device

  • write to an output device

  • read a value from storage

  • write a value to storage

  • "do math"

  • branch

  • loop (repeated branching)

It's branch day!

  • read from an input device

  • write to an output device

  • read a value from storage

  • write a value to storage

  • "do math"

  • branch

  • loop (repeated branching)

time to branch out

Up to now, we've written purely sequential programs

name = input("Who the heck are you? ")
print(f"Oh. Hi, {name} - I didn't recognize you.")

hair_changed = input("Have you done something with your hair?")

Wouldn't it be nice here to do something different based on the user's reply?

Of course it would.
That was a rhetorical question.

if, if-else, if-elif-else statements

if, if-else, if-elif-else statements

name = input("Who the heck are you? ")
print(f"Oh. Hi, {name} - I didn't recognize you.")

hair_changed = input("Have you done something with your hair? ")

if hair_changed == "y":
  print("Well THAT explains my confusion.")
  
print("Enough chitty-chat. Let's grab some vitamin D.")

Let's add an if

4. and a block of code to run if the condition is true

2. and a condition

1. we'll need an if, naturally

3. and a colon, 'cause Python

...and don't forget the indent!

What happens when we run this with a "y"? A not "y"?

🙋🏻‍♂️❓🙋🏻‍♀️What kind of operator is ==?

name = input("Who the heck are you? ")
print(f"Oh. Hi, {name} - I didn't recognize you.")

hair_changed = input("Have you done something with your hair? ")

if hair_changed == "y":
  print("Well THAT explains my confusion.")
else:
  print("Oh.")
  print("This is awkward.")
  print("...")
    
print("Enough chitty-chat. Let's grab some vitamin D.")

Let's make it if-else

3. and a block of code to run when the condition is FALSE

1. add an else

2. another colon. yay.

Again, try this with a "y", then a not "y".

This dialog would sound more natural if we react to y, n, and anything else in different ways.

name = input("Who the heck are you? ")
print(f"Oh. Hi, {name} - I didn't recognize you.")

hair_changed = input("Have you done something with your hair? ")

if hair_changed == "y":
  print("Well THAT explains my confusion.")
elif hair_changed == "n":
  print("Oh.")
  print("This is awkward.")
  print("...")
else:
  print("Pardon?")
  
print("Enough chitty-chat. Let's grab some vitamin D.")

if-elif-else

Try this with a "y", then a "n", then something else.

now you try

BASE_COST = 12.00
colour = input("What tshirt colour do you wanna order? ")

if colour == "red" or colour == "blue":
  discount = 0.1
elif colour == "black":
  discount = 0.15
elif colour == "green":
  discount = 0.05
else:
  discount = 0

cost = BASE_COST * (1 - discount)

What value will cost have if a user enter "blue" at the prompt?

How about "Black"?

How about "green"?

Let's take this to Python Tutor and trace it. Keep an eye on discount!

branching boo-boos

Can you spot 'em?

branching boo-boos

tank_empty = True

if tank_empty == True:
  print("The tank...she be empty!")
else:
  print("We got gas - let's roll!")

boo-boo #1

There is NO need to do this kind of comparison - since tank_empty and happy are booleans, just use them!

...
if tank_empty:
  print("The tank...she be empty!")
...
happy = False

if happy == False:
  print("Wassup? You look down.")
else:
  print("You look pretty chipper.")
...
if not happy:
  print("Wassup? You look down.")
...

branching boo-boos

if lives_left > 0:
  print("Continue?")
else lives_left <= 0:
  print("Game over!")

boo-boo #2

Elses never need a condition - if the if condition doesn't trigger, into the else we go!

if lives_left > 0:
  print("Continue?")
else:
  print("Game over!")

branching boo-boos

# want to return true if dial between 1 and 10
if 1 <= dial <= 10:
  print("The dial is pleased.")

boo-boo #3

Sorry - while you can do this in math class...you can't do it here!
We want to say "if the dial is greater than/equal to 1 AND the dial is less than/equal to 10"... so use THAT instead!

# want to return true if dial between 1 and 10
if dial >= 1 and dial <= 10:
  print("The dial is pleased.")

branching boo-boos

another way to write this particular case that makes thing even more obvious

# want to return true if dial between 1 and 10
if 1 <= dial and dial <= 10:
  print("The dial is pleased.")

dial now looks visually between 1 and 10

branching boo-boos

# want to do something if user picks black or white
if user_choice == "black" or "white":
  print("Your world is very...plain.")

boo-boo #4

It'd be awesome if we could do this...but we can't. :(
We want to say "if the choice is black OR the choice is white"... so use THAT instead!

# want to do something if user picks black or white
if user_choice == "black" or user_choice == "white":
  print("Your world is very...plain.")

branching boo-boos

if amount < 0:
  print("Invalid amount.")
elif amount >= 0 and amount < 40:
  print("Add some stuffs.")
else:
  print("Yay! Free stuffs.")

boo-boo #5

Wait a sec...if we got to the elif, that means we got past the if, right?
In that case amount MUST be >= 0 already, so we don't have to check again!

if amount < 0:
  print("Invalid amount.")
elif amount < 40:
  print("Add some stuffs.")
else:
  print("Yay! Free stuffs.")

boolean-returning functions

boolean-returning functions

I love these guys...they really go a long way towards making code expressive.

boolean-returning functions

Let's take a look at lab-10.
I wanna show you a few things.

boolean-returning functions

Task
Make a function is_factor(x, y) that returns True if x is a factor of y (and False otherwise).

Remember Polya? He's still a thing, you know - not just a one-shot.

  1. Understand that problem? Do you remember what "x is a factor of y" means...or at least give examples?
  2. Have a plan?
  3. Have a way to implement it?
  4. Know how to test it?

boolean-returning functions

Task
Make a function is_factor(x, y) that returns True if x is a factor of y (and False otherwise).

Now that you know if/if-else/if-elif-else,
you might be tempted to do this:

def is_factor(x, y):
  if y % x == 0:
    return True
  else:
    return False

boolean-returning functions

This "works"...but is wordier than it needs to be - and a pattern you will see frequently and should be on guard for.

def is_factor(x, y):
  if y % x == 0:
    return True
  else:
    return False

Task
Make a function is_factor(x, y) that returns True if x is a factor of y (and False otherwise).

boolean-returning functions

When that condition is False, what is returned?

def is_factor(x, y):
  if y % x == 0:
    return True
  else:
    return False

Task
Make a function is_factor(x, y) that returns True if x is a factor of y (and False otherwise).

When the condition in the if is True, what is returned?

In this "long way" pattern:

boolean-returning functions

Use this pattern instead - and notice the behaviour of this "short way" is identical to the long way!

def is_factor(x, y):
  return y % x == 0

Task
Make a function is_factor(x, y) that returns True if x is a factor of y (and False otherwise).

Polya's 4th step suggests we should test our function...let me show you some easy ways to do that.

def is_factor(x, y):
  if y % x == 0:
    return True
  else:
    return False

You can import your source files into the REPL!

boolean-returning functions

One way: Use the REPL

Crude, but works!

boolean-returning functions

Another way: Use asserts

Notice however you decide to test, you need to figure out at least a few test cases yourself - that's part of programming!

Faith-based programming is NOT reliable.

boolean-returning functions

Continuing with the lab....

Task
Make a function is_even(x) that returns True if x is even (and False otherwise).
The catch: use is_factor(x, y) in your solution.

boolean-returning functions

Let's say you're a bit confused over that catch. You could still go ahead and try it without.

def is_factor(x: int, y: int) -> bool:
  return y % x == 0
  
def is_even(num: int) -> bool:
  return num % 2 == 0

"divides evenly by 2" => remainder is 0.

Something is even if it divides evenly by 2, so you decide to write this:

boolean-returning functions

But to say "x divides evenly by 2" is the same as saying "2 is a factor of x" - and we have a function that does that...heck, the condition is the same!

def is_factor(x: int, y: int) -> bool:
  return y % x == 0
  
def is_even(num: int) -> bool:
  return num % 2 == 0

Task
Make a function is_even(x) that returns True if x is even (and False otherwise).
The catch: use is_factor(x, y) in your solution.

boolean-returning functions

So just use is_factor!

def is_factor(x, y):
  return y % x == 0
  
def is_even(x):
  return is_factor(2, x)

Task
Make a function is_even(x) that returns True if x is even (and False otherwise).
The catch: use is_factor(x, y) in your solution.

Using functions in other functions is a VERY common thing. Look for opportunities to do it yourself whenever you can!

One more.

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 > 0

Task
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.

Made with Slides.com