Functions

  • so far: we have called functions.
    • examples: print(), math.ceil()
  • this week
    • we will learn to write our own functions
  • function definition
  • function call
  • keywords: def and return
  • example of a function definition:
def greeting():
    print("Have a nice day!\n")

Function Definition

  • function name
    • lower case letters and underscore
  • format
    • def function_name():
    • parameters (x is a parameter)
    • indent code
    • return (optional)
def is_even(x):
    return x % 2 == 0

Calling Functions

  • call a function to execute the function
  • when called, the code inside the function is executed
  • 149 is an argument
greetings()
if is_even(149):
    print("This shouldn't happen")
else:
    print("149 is an odd number")

Look at the example again

def is_even(x):
    return x % 2 == 0
if is_even(149):
    print("This shouldn't happen")
else:
    print("149 is an odd number")

More about functions

  • why functions?
    • do multiple times and avoid duplicate code
    • improves readability
  • if a function does return a value, None is returned
    • can use return with no value
    • call a void function if no return statement
  • a function can have 0, 1 or multiple parameters

More Examples

def analyze(number):
    if number == 0:
        return "Zero!"
    if number > 0:
        return "Positive"
    return "Negative"


if __name__ == "__main__":
    print("an example", analyze(-1))

Mutliple Paramters

def sales(grocery_store, item_on_sale, cost):
    print(grocery_store + " is selling " + item_on_sale + " for " + cost) 
if __name__ == "__main__":
    sales("The Farmer’s Market", "bananas", "$1")

Multiple Return Statements

def check_leap_year(year):
    if year % 4 == 0:
        return str(year) + " is a leap year."
    else:
        return str(year) + " is not a leap year."

if __name__ == "__main__":
    year_to_check = 2024
    print(f'{check_leap_year(year_to_check)}')

Visualizing Execution

def model_two(word):
    ans = word * len(word)
    print(ans)

def main():
    print("Starting main...")
    w = input("Enter a word: ")
    model_two(w)
    print("All done!")

main()
  • open Python Tutor and copy the above into the window
  • press Visualize Execution
  • press Nextand step through the execution

Checkpoint 1

  • modify model_two()
  1. add a paramter named times
  2. replace len(word) with times
  3. update the function call in main()
  • visualize in Python Tutor

Checkpoint 2

def model_three(word):
    ans = word * len(word)
    return ans

def main():
    print("Starting main...")
    w = input("Enter a word: ")
    result = model_three(w)
    print(result)
    print("All done!")

main()
  • what has changed?
    • notice the return
    • notice the function call to model_three()

Checkpoint 3

  • What does the following code print?
def calculate(w, x, y):
    a = x
    b = w + 1
    return a + b + w

print(calculate(1, 2, 0))

Which of the following contains a function call?

(1) type(4.5)

(2) def add_one(x):
        return x + 1

(3) area(2, 9)

(4) print("Hello")

Dynamic Typing

  • python uses dynamic typing
    • type is determined when the program executes
    • python uses duck typing
  • some language use static typing (e.g., Java, C)
def multi(x, y):
    return x * y

if __name__ == "__main__":
    result = multi(5, 7)
    print(result)
    result = multi(5, "yes")
    print(result)

Function Returning Multiple Values

  • unpacking is an operation that allows a statement to perform multiple assignments
    • lines up in order
def two_things():
    str = "Sharon"
    number = 14
    return str, number
 
# Driver code to test above method
print(two_things())
name, value = two_things()
print(name, value)

List ( a Collection datatype )

  • Next week will cover in detail
  • list is an ordered sequence of elements
  • a list is changable; meaning can change, add or remove elements
    • enclosed by []
    • seperate by commas
    • declare list by
      • []
      • list()
lst = [1, 1.23, True, 'hello', None]
print(lst)

>>>
[1, 1.23, True, 'hello', None]
lst = list((1, 1.23, True, 'hello', None)) # notice the double round brackets
print(lst)
print(len(list))
print(lst[0])

>>>
[1, 1.23, True, 'hello', None]
5
1

Readability of Code with Functions and Modular Development

def steps_to_feet(num_steps):
    feet_per_step = 3
    feet = num_steps * feet_per_step
    return feet

def steps_to_calories(num_steps):
    steps_per_minute = 70.0
    calories_per_minute_walking = 3.5

    minutes = num_steps / steps_per_minute
    calories = minutes * calories_per_minute_walking
    return calories

if __name__ == "__main__":
    steps = int(input('Enter number of steps walked: '))
    feet = steps_to_feet(steps)
    print(f'Feet: {feet}')
    calories = steps_to_calories(steps)
    print(f'Calories: {calories}')

Function calls in expressions

def compute_square(num_to_square):
    return num_to_square * num_to_square

if __name__ == "__main__":
    c2 = compute_square(7) + compute_square(9)
    print(f'7 squared plus 9 squared is {c2}')

Local variables and scope

- look back at previous examples

Scope of Variable and Functions

  • What does the following code print?
def change(x):
    x = 456

x = 123
change(x)
print(x)

More on Scope

  • global variables
    • use sparingly
    • avoid local variables (including parameters) from having the same identifier
    • can not modify a variable from a high-level scope
    • can access the value of a variable from a high-level scope
  • global keyword
    • provides a means to modify a high-level scope variable
    • good programming design rarely modifies a global inside a function

Globals

value1 = 10
value2 = 20
def add_values(one, two):
    return one+two
def main():
    sum = add_values(value1, value2)
    print(sum) 
main()

OR

value1 = 10
value2 = 20
def add_values():
    return value1 + value2
def main():
    sum = add_values()
    print(sum) 
main()

Global and Assignments: What happens?

  • is counter local or global?
counter = 0

def increment(num):
    counter = num     # is counter local or gloabl?

def main():
    increment(4)
    print(counter)
    
main()

Globals

counter = 0

def increment(num):
    global counter   
    counter += num

def main():
    increment(4)
    print(counter)
    
main()
  • comment out the line global counter, what happens?

local vs global

  • what is the output
  • message from Thonny

Line 3 : Redefining name 'counter' from outer scope (line 1)
It looks like the local variable is hiding a global variable with the same name.
Most likely there is nothing wrong with this. I just wanted to remind you that you can't access the global variable like this.

counter = 0

def increment(counter):
    counter = counter + 1
    print(counter)

def main():
    increment(4)
    print(counter)
    
main()

DocStrings

def deposit(acct, amount):
    """Deposit money into an account.

    Args:
        acct (int): account number
        amount (float): money to deposit

    Returns:
        float: updated account balance
    """
  • One-line summary after """
  • Args: section (if applicaable)
  • Returns: section (if applicable)

help() Function

  • When in the shell, help() is always there!
  • The help() function shows the docstring
  • Works on modules, functions, keywords, etc.
  • Can also run help() without an argument!

Extra slides

Mathematical Functions

  • what type is centimeters?
  • what type is feet?
  • what is wrong with the commented line?
CM_PER_INCH = 2.54
INCHES_PER_FOOT = 12

def height_US_to_cm(feet_p, inches_p):
    total_inches = feet_p * INCHES_PER_FOOT + inches_p
    cm = total_inches * CM_PER_INCH
    return cm

feet = int(input("how many feet? "))
inches = int(input("how many inches? "))
centimeters = height_US_to_cm(feet, inches)
print(f'Centimeters: {centimeters:.2f}')
# print(feet_p)
  • Visualize in Python Tutor
def woot(x):
    print(x)
    yar(x + 1)
    print(x)
    yar(x + 2)

def yar(y):
    if y > 5:
        print(y * 2)
    else:
        foo(y + 1)

def foo(z):
    print(z - 1)
    yar(z + 1)

woot(3)