Day 9: Advanced Functions & last midterm 1 practice

back · home · slides · CMSC 201 (Fall 2024) @ UMBC · scopes & such

CMSC 201: Advanced Functions and more exam

Agenda:

  • HW4 still here!
  • "Fun": old websites
  • Who cares? (AKA: what will we make)
  • Advanced functions! Scopes!
  • More pratice exam stuff!
  • Goal: Become functional legends, maybe have fun :)

    My email is: sdonahue@umbc.edu (Shane Donahue), office hours Tu/Th ITE 373 2-3PM.

    HW4

    HW4 is out and still due Friday 2024-10-04 at 11:59:59 PM :) You know everything you need to know for it! Don't use functions in HW4.

    Reminders: don't use functions in HW4. Also please use if __name__ == "__main__":!

    Midterm #1

    Midterm #1 is still October 9th for M/W October 10th for Tu/Th! There is no make-up time! Please don't miss it :(! I have no power to give you make-up times. TAs will be in the room, administering the test. It is during the lecture section (so, this time).

    Reminder: If you have SDS accomodations (e.g., extra time or reduced distractions), please book that room and let them know you plan to take the test there! The room here will be very quiet though, so there won't be many auditory distractions.

    "Fun": the "small web"

    Tired of big websites? Sick of google pushing its advertiser-friendly agenda? Miss the 90s and 2000s where everyone had their own personal website that actually had personality?

    Look no further! The "small web" is still well and alive-- it's just hard to find.

    Two of my favorite "small web" search engines: search.marginalia.nu and wiby.me. Let's take some risks and look through some sites...

    Who cares (about advanced functions)?

    Functions are very very useful. Let's actually do that chatbot this time, hopefully. Unless we run out of time (:

    https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/4c404100-0353-478d-9610-89fcda34b8e6/topbots-chatbots-1-flowers-brokenrecord-cut-opt.png Screenshot of user being frustrated by a bad chatbot

    Functions Review

    Functions are one of most important programming concepts. Essentially: take some code and make it re-usable in different situations!

    Functions take some input, and usually have some output.

    def make_excited(input_var):
    	print(input_var + "!!!")
    
    make_excited("Hi") # Will print: Hi!!!
    make_excited(2) # Error
    make_excited("I am great today") # Will print: I am great today!!!

    def is the keyword that defines functions. You already use Python functions without knowing it: print is a function!

    Every time we "call" make_excited, all the code in that function will be executed, then we will continue on from after where we called it.

    Last time, we took our word replacing program and made a function to replace the words for us. We turned this:

    input_sentence = input("Give sentence: ")
    input_split = input_sentence.split()
    
    for word_index in range(len(input_split)):
        if "apple" in input_split[word_index].lower():
            input_split[word_index] = "banana"
        elif "banana" in input_split[word_index].lower():
            input_split[word_index] = "government-sponsored BANANA(TM)"
    
    print(" ".join(input_split))

    Into this:

    input_sentence = input("Give sentence: ")
    input_split = input_sentence.split()
    
    def replace_word(word, find, replace):
        if find in word.lower():
            return replace
        return word
    
    for word_index in range(len(input_split)):
        input_split[word_index] = replace_word(input_split[word_index], "apple", "banana")
        input_split[word_index] = replace_word(input_split[word_index], "banana", "government-sponsored BANANA(TM)")
        input_split[word_index] = replace_word(input_split[word_index], "hate", "love")
        input_split[word_index] = replace_word(input_split[word_index], "worst", "best")
    
    print(" ".join(input_split))

    Very easy to add new words 😌

    Challenge: Boba shop time! You run a boba shop. Use a function to calculate the rolling total. Take their order as a list of strings, and quit when they input "and that's it". All sweetener is 50 cents, boba is a dollar, and any tea is four dollars.
    def add_item(item_name, order_list):
        price = 0
        valid = False
        if "sugar" in item_name or "sweet" in item_name:
            price = 0.5
            valid = True
        elif "tea" in item_name:
            price = 4
            valid = True
        elif "boba" in item_name:
            price = 1
            valid = True
                
        if valid:
            order_list.append(item_name)
        else:
            print("What is that?! I don't know what that is.")
    
        return price
    
    total_order = []
    total = 0
    user_input = input("Welcome to Boba Inc, what would you like?: ")
    while user_input != "and that's it": 
        total = total + add_item(user_input, total_order)
        user_input = input("and?: ")
    
    print("Ok, your total is", total, total_order)

    Functions arguments, scope, and pain

    Same as before: mutable objects in Python are "passed by reference" (modifying the object does modify the variable in its parent scope). Immutable objects are "passed by value" (modifying the value does not modify the variable in its parent scope).

    Scope: what context(s) a variable is valid for.

    You always start in the global "scope" when you start your Python file. Every function you write has its own local "scope", which contains everything from the global scope, but NOT vice versa.

    def print_x():
        x = 10
        print(x)
    
    print_x()
    y = x + 5 # What happens?
    y = x + 5
        ^
    NameError: name 'x' is not defined

    The above produces an error! As soon as you try to use "x" outside of the local scope of the function, it throws an error, because x does not exist outside of that function.

    What about this one?

    x = 10
    
    def print_x():
        print(x)
    
    print_x()
    y = x + 5 # What happens?

    The global context "x" is able to be used in print_x. No error occurs.

    Scopes and mutable vs immutable: Which ones modify the variable?

    def double_value_A(x):
    	return x*2
    
    def double_value_B(x):
    	x = x*2
    
    my_num = 5
    
    # Option one:
    double_value_B(my_num)
    print(my_num) # Prints what?
    
    # Option two:
    my_num = double_value_A(my_num)
    print(my_num) # Prints what?
    

    double_value_B modifies an immutable value in a local context. It will not modify my_num. double_value_A returns the modified variable, and lets the caller (global context) reassign that label to the new value. This is just like when we modify the temporary variable inside a for loop (except complicated by global and local scopes):

    test_list = [1, 2, 3]
    
    for x in test_list:
        # Does nothing to the original list
        x *= 2
    
    for x in range(len(test_list)):
        # Does modify the original list!
        test_list[x] = test_list[x] * 2

    Ok... what about this one?

    x = 10
    
    def print_x():
        x += 20
        print(x)
    
    print_x()
    y = x + 5
    print(y) # What happens?
    # Exact error depends on your version of Python
    UnboundLocalError: local variable 'x' referenced before assignment

    Error! Python, in this case, will stop us from assigning a new value to an immutable global! We attempted to mutate (change) an immutable variable. That's a no-go!

    What about this disaster:

    x = 10
    
    def print_x():
        y = x
        y += 20
        print(y)
    
    print_x()
    y = x + 5
    print(y) # What happens?

    No errors, but not what you may have expected! It mutated it in our local scope only, and left our global scope alone. y exists in both a local and global scope. The local one does NOT overwrite the global one.

    Another one! What do we think this one would do?

    cool_list = [1,2,3,4]
    
    def add_to_list(new_num):
    	cool_list.append(new_num)
    
    add_to_list(new_num)
    print(cool_list)

    This works, since even though we're using a global scope variable in a local scope, it's mutable, so we can modify it like normal. However, this is a bad practice: we don't want to mutate global variables in a local context. That can get really messy when you don't know what functions modify what variables.

    It's best practice to include every variable needed for a function in its parameters. (This is called a "pure" function).

    Other things you can do with functions, but shouldn't

    Yes, you can call your own function in a function. That's called recursion and it's one of the last topics of the class.

    You can also pass functions as an argument to functions! Please don't do that in this class.

    Let's write that chatbot

    Let's make a conversational bot, with two functions: one for choosing a random response, and one for asking for an explanation of the user's input. (Inspired by ELIZA-- chatbot from 1967).

    import random
    
    def respond_basic():
        choice = int(random.random() * 3)
        if choice == 0:
            return "Why do you say that?"
        elif choice == 1:
            return "Can you elaborate?"
        else:
            return "What makes you feel like that?"
    
    def respond_with_input(user_input):
        choice = int(random.random() * 2)
        if choice == 0:
            return "Can you explain what you meant by: " + user_input
        return "How does it make you feel that " + user_input
    
    user_input = input("ELOZA: How can I help you today?\nYOU: ")
    while user_input != "bye":
        choice = int(random.random() * 2) 
        if choice == 0:
            response = respond_basic()
        else:
            response = respond_with_input(user_input)
        user_input = input("ELOZA: " + response + "\nYOU: ")

    Exam practice

    Fall 2023 Midterm 1 Study Guide/Answers

    I anticipate the programming free response to be the hardest. I'll have practice problems in future classes, but if you want to practice now, you can speedrun re-solve your homework, or check out the problems on codingbat (https://codingbat.com/python).