Published: 2024-07-27

Lesson 5 - Functions and Modules

Time To Complete: 2 hours


Programmers are lazy. Re-using working code in the world of programming is very important. If you don’t then your fingers will probably fall off from typing. you can re-use useful code by writing functions.

Using Functions

Functions have already been used in other lessons. The range() function returns values from x to y.

#list of items from 0 up to 100
print(list(range(0,100)))

You could type out every value from 0 up to 100, but if you want to create a bigger list that would take a lot more time. If you use functions you could just as easily create a list with thousands of numbers.

def print_range(r):
    print(list(range(1,r + 1)))

#print values 1 to 100
print_range(100)

Functions are chunks of code that tell Python to do something. They are one way to reuse code. You can use them over and over again. Functions are handy for simple programs and essential for complex programs with thousands of lines of code.

Parts of a Function

A function has three parts: name, parameters, and a body.

def myfunc(myname):
    print("hello" + myname)

The name of this function is myfunc. It has a single parameter, myname, and its body is a block of code that follows the line starting with def, which is short for define. A parameter is a variable that exists only while a functions is being used.

You can run a function by calling its name and using () around the parameter value.

myfunc("Jake")

Functions can take multiple values as parameters.

def myname(fname, lname):
    print('Hello' + " " + fname + " " + lname)
    
myname("John", "Smith")

The two values are separated by comma like so, myname("John", "Smith").
You can also create some variables first and pass them into the function.

fname = "John"
lname = "Smith"

myname(fname , lname)

A function is used to return a value using the return statement.

Calculating Savings

You deliver newspapers every morning. You make $150 per week on your paper route. You already had $20 bucks in your pocket and you spent $40 bucks over the weekend. Write a function that returns your savings as an integer.

def savings(pocket_money, paper_route, spending):
    return pocket_money + paper_route - spending

Code

This function returns three parameters. It adds the first two parameters (pocket_money & paper_route) and subtracts the last parameter (spending). The function returns the result and it can be stored in a variable.

Now, if you try to run this function as is nothing happens. This is because you have to call the function. This can be done by typing the name of the function and by providing values for the parameters.

money = savings(20, 150, 40)
print(money)

You can even save specific instances of a function, savings(20,150,40), as an object and reference that object later like in the example above.

Full Code:

def savings(pocket_money, paper_route, spending):
    return pocket_money + paper_route - spending

money = savings(20, 150, 40)
print(money)

Variables and Scope

Variables can be created inside of functions. This can make writing functions with a lot of data a lot easier for developers, however, variables inside the body of a function can’t be used again. This is because variables created inside of a function only exist within that function. In the world of programming this is referred to as scope.

Let’s take a look at a simple function that uses a couple of variables.

def var_test():
    first = 10
    second = 20
    return first * second

This function simply multiplies the value of first with the value of second and returns the result. If you call this function using print you get 200.
What happens if you try to print the value of first and the value of second?

def var_test():
    first = 10
    second = 20
    return first * second

print(first)
print(second)
print(var_test())

If you try to execute the code above, you might notice the squiggle lines underneath print(first) and print(second). This is python saying “Hey, I don’t know what these variables mean outside of var_test().” If you ignore python’s warning and run the code anyway you will be met with an error that may look like this:

Traceback (most recent call last):
  File "<pythonshell>", line 12, in <module>
    print(first)
NameError: name 'first' is not defined.

A variable defined inside of a function has a different scope than a variable defined outside of a function.

Now let’s declare a variable outside of a function and then call it inside of a function.

txt = 'hey'

def myfunc():
    print(txt)

myfunc()

In the previous example, first and second could not be used outside of the function because they were declared locally, or inside of a function. In the example above the variable txt can be used inside of the function because it was declared globally. An easy way to remember this is that, in python, variables declared globally can be used inside functions. Variable declared locally cannot be used outside of functions.

Building a spaceship

Suppose you were building a spaceship out of tin cans. You think you can flatten 2 cans a week to create the walls for your ship. You’ll need 500 cans to fully furnish your ship. Write a function to work out how long it will take to flatten 500 cans.

code:

def build_spaceship(cans):                                              #1
    total_cans = 0                                                      #2
    for i in range(1,53):                                               #3
        total_cans = total_cans + cans                                  #4
        print("Week " + str(i) + " = " + str(total_cans) + " cans" )    #5

explanation:

On 1, define the function build_spaceship(cans). build_spaceship() takes one parameter, cans. Inside of the function on 2, the variable total_cans represents the number of cans that have been flattened. At the start there will be 0. The for loop starting on 3 loops through the number of weeks in one year. After each iteration (or after each week) 4 calculates the number of cans flattened by adding the total_cans variable and the number of cans flattened that week. 5 prints the number of cans flattened that week.

After 1 year (52 weeks) only 104 cans have been flattened. 500 cans are needed, so there is still a long way to go. Let’s speed things up by calling the function build_spaceship() and passing in a value greater than 2 into cans.

build_spaceship(13)

If 13 cans get flattened a week, then after 1 year you will produce 676 cans for your spaceship. By week 39, 507 cans had been flattened, why overproduce? Let’s tweak the function to stop at 500 total cans.

def build_spaceship(cans):
    total_cans = 0
    week = 0
    while total_cans < 500:
        total_cans = total_cans + cans
        week += 1
        print("Week " + str(week) + " = " + str(total_cans) + " cans" )
        

build_spaceship(13)

To do this very easily you can change the loop from for i in range(1,53): to while total_cans < 500:. Additionally, create a new local variable called week and increment week by 1 at the end of each iteration to keep track of time.

Modules

Modules are used to group functions, variables and other things together into larger and more powerful programs. Python has some built in modules and others you can download off of the internet.

Let’s import a function that will allow us to display the current time.

import time

print(time.asctime())

The import command is used to tell python that you want to use the time module. You can use functions that are available in this module using the dot symbol. In this case, time.asctime(). The function asctime() is apart of the time module and it returns the current date and time as a string.

Programming Problems

1. Basic Moon Weight Function

In lesson 3, one problem was to create a loop to determine what the weight of an object would on the moon if it increased in size over a 15 year period. The for loop used to solve the problem in lesson 3 could easily be turned into a function. Revisit that problem, and write a function to calculate an object’s weight on the moon.

solution 1:

def moon_weight(weight):
    moon_factor = .165
    return weight * moon_factor

print(moon_weight(30))

solution 2:

def moon_weight(weight):
    moon_factor = .165
    print("weight on the moon: " + str(weight * moon_factor))

moon_weight(30)

2. Moon weight function in years

Now let’s completely rewrite the moon weight problem from lesson 3 as a function.

There is a bucket of rocks that weighs 145 pounds. If 1 lb of rocks is added every year, how much would the bucket weigh on the moon after 15 years?

def moon_weight(weight, added, years):
    moon_factor = .165
    for i in range(years):
        weight += added
        moon_weight = weight * moon_factor
        print(str(i + 1) + ". " + str(moon_weight))

moon_weight(30, 1, 20)

3. Moon Weight Program

Now let’s take it one step further. Instead of a function that runs once, write a program using input() to prompt the user to enter values for the function.

Try this one on your own. Reference the calculator program from lesson 4. Don’t over think it. All you have to do is put all of the pieces together.

Challenge

Make the program re-usable. Write the program in a way that allows the user to continuously run the program without having to restart.

Hint: refer to the simple calculator program in lesson 4.

3. Solution

This problem can have multiple solutions. Here are a few solutions:

solution 1

def moon_weight(weight, added, years):
    moon_factor = .165
    for i in range(years):
        weight += added
        moon_weight = weight * moon_factor
        print(str(i + 1) + ". " + str(moon_weight))

weight = int(input("enter the starting weight: "))
added = int(input("enter the number of lb(s) added each year: "))
years = int(input("enter the number of years: "))

moon_weight(weight, added, years)

solution 2

def moon_weight():
    moon_factor = .165
    weight = int(input("enter the starting weight: "))
    added = int(input("enter the number of lb(s) added each year: "))
    years = int(input("enter the number of years: "))
    for i in range(years):
        weight += added
        moon_weight = weight * moon_factor
        print(str(i + 1) + ". " + str(moon_weight))

moon_weight()

solution 3

def moon_weight(weight, added, years):
    moon_factor = .165
    for i in range(years):
        weight += added
        moon_weight = weight * moon_factor
        print(str(i + 1) + ". " + str(moon_weight))

moon_weight(int(input("enter the starting weight: ")),
            int(input("enter the number of lb(s) added each year: ")),
            int(input("enter the number of years: ")))

Note: Solution 3 works, but it is not as readable as the other two.