Grade by Grade
A. Programming Concepts and Skills · Arrays and Subprograms

Writing Your Own Functions

A3.2 A4.2 A4.3About 70 minutes
Learning goals
  • I can define a function with def, parameters, a body and a return statement, and call it.
  • I can explain the difference between a parameter and an argument, and between return and print.
  • I can follow the flow of control into a function and back out.
  • I can name and document a function using professional conventions (a verb-style snake_case name and a docstring).

Words to know

function definition
The def block that creates a function: its name, parameters and body. It does not run until the function is called.
parameter
A variable named in the function definition that receives a value when the function is called, e.g. temp_c in def wind_chill(temp_c, wind_kmh).
argument
The actual value passed in a call, e.g. -10 in wind_chill(-10, 20).
return statement
return value ends the function and sends the value back to the caller.
procedure
A subprogram that performs an action but does not return a value. In Python it is a function that returns None.
docstring
A string in triple quotes on the first line of a function body that explains what the function does, its parameters and what it returns.
flow of control
The order in which a program's statements run, including jumps into and out of functions.

Write it once, use it everywhere

A weather app for Northern Ontario shows the wind chill on the home screen, in the hourly forecast and in a warning message. The calculation is a long formula. If you copy it into three places and someone finds a mistake, you must fix it three times, and you will probably miss one.

A function solves this. You write the formula once, give it a name, and call it wherever you need it. The curriculum asks you to write your own subprograms, called functions or procedures, that use parameter passing and appropriate scope. This lesson covers writing and calling them; the next two cover parameters and scope in depth.

Remember from Grade 9 math

In Grade 9 you wrote one-line functions such as def cost(h): return 28 + 6 * h and called them with cost(5). Now you will write longer functions, with decisions and loops in their bodies, and document them like a professional.

The parts of a function

  • def starts the definition.
  • The name follows the same rules as variable names. By convention it is snake_case and often a verb or a description of the result: wind_chill, count_below, print_banner.
  • Parameters go in brackets, separated by commas. They are variables that will receive values when the function is called. A function can have no parameters: def show_menu():.
  • A colon ends the header line.
  • The body is indented (4 spaces). Its first line should be a docstring in triple quotes saying what the function does.
  • return value ends the function and sends the value back.
def area_of_rink(length, width): """Return the rink's area in m².""" area = length * width return areakeyword deffunction nameparameterscolondocstringindentedbodyreturn valuecall: a = area_of_rink(60, 26) → a is 1560
The parts of a function definition. The call area_of_rink(60, 26) passes the arguments 60 and 26 into the parameters length and width; the function returns 1560. (60 m by 26 m is about the size of an NHL ice surface.)

Defining is not running

A def block only creates the function. Nothing inside runs until the function is called. When Python reaches a call:

  1. It evaluates the arguments.
  2. It jumps to the function and gives each parameter the value of its argument, in order.
  3. It runs the body until it reaches return (or the end of the body).
  4. It jumps back to where the call was, and the call is replaced by the returned value.

Because Python reads a file from top to bottom, a function must be defined before the line that calls it runs. Calling it too early gives NameError.

1 def double(n):2 result = n * 23 return result45 x = 76 y = double(x)7 print(y)① run line 5: x = 7② line 6 calls double(7): jump up③ n = 7 (parameter gets argument)④ line 2: result = 14⑤ line 3: return 14, jump back⑥ y = 14⑦ line 7 prints 14
Flow of control. Line 1 only creates the function (its body, lines 2 and 3, does not run yet), so the first real work happens at line 5. The call on line 6 jumps into the function (solid arrow), the parameter n receives 7, and return jumps back (dashed arrow) with the value 14.
Worked example

Example 1: A wind chill function

Environment and Climate Change Canada reports the wind chill index with the formula W = 13.12 + 0.6215T − 11.37V^0.16 + 0.3965T·V^0.16, where T is the air temperature in °C and V is the wind speed in km/h. Write a documented function and use it.

  1. Choose a clear name and parameter names that include the units: wind_chill(temp_c, wind_kmh).
  2. Compute V^0.16 once and store it in a local variable v, so the formula is easier to read.
  3. Return the rounded value instead of printing it, so the caller can print it, compare it or store it.
  4. The program below calls the function three times with different arguments.

Output: -18, -33 and Frostbite risk is high: -48.

def wind_chill(temp_c, wind_kmh):
"""Return the wind chill index, rounded to a whole number.
Uses the formula from Environment and Climate Change Canada.
temp_c: air temperature in °C; wind_kmh: wind speed in km/h.
"""
v = wind_kmh ** 0.16
w = 13.12 + 0.6215 * temp_c - 11.37 * v + 0.3965 * temp_c * v
return round(w)
print(wind_chill(-10, 20))
print(wind_chill(-20, 30))
feels = wind_chill(-30, 40)
if feels <= -40:
print("Frostbite risk is high:", feels)

The function from Example 1. The docstring explains the purpose, the source of the formula, and the units of each parameter.

return vs. print

This is the most important idea in the lesson. print shows a value on the screen for a person. return hands a value back to the program. A value that is only printed cannot be stored, added or compared.

A function with no return (or a bare return) gives back None. Such a subprogram is sometimes called a procedure: it is used for what it does (for example printing), not for a value.

def print_banner(title):
"""Print title between two lines of = signs."""
print("=" * len(title))
print(title)
print("=" * len(title))
result = print_banner("Snow Report")
print(result)

Output: the banner (===========, Snow Report, ===========) and then None. print_banner is a procedure: it does its job, but there is no value to keep.

Worked example

Example 2: Several return statements

In Ontario, a percentage mark of 80 to 100 is Level 4, 70 to 79 is Level 3, 60 to 69 is Level 2 and 50 to 59 is Level 1. Write a function that returns the level for a mark.

  1. A function can have several return statements. The first one that runs ends the function immediately.
  2. Check from the top down: if mark >= 80, return "Level 4"; otherwise check >= 70, and so on.
  3. If no test passes, the last line returns "below Level 1". No else is needed, because every earlier branch already returned.
  4. Code: def achievement_level(mark):     """Return the Ontario achievement level for a percentage mark."""     if mark >= 80:         return "Level 4"     elif mark >= 70:         return "Level 3"     elif mark >= 60:         return "Level 2"     elif mark >= 50:         return "Level 1"     return "below Level 1" for m in [92, 74, 50, 49]:     print(m, achievement_level(m))

92 Level 4, 74 Level 3, 50 Level 1, 49 below Level 1

Functions that work on lists

A parameter can hold a whole list. This turns the algorithms from earlier lessons into reusable tools:

def average(values):
"""Return the mean of a non-empty list of numbers."""
total = 0
for v in values:
total += v
return total / len(values)
marks = [78, 91, 66, 85]
print(average(marks))
print(average([3, 4]) + average([10]))

Output: 80.0, then 13.5 (3.5 + 10.0). Each call runs the loop on a different list.

When a function goes wrong

  • NameError: name 'wind_chill' is not defined: the call runs before the def, or the name is misspelled.
  • TypeError: wind_chill() missing 1 required positional argument: 'wind_kmh': too few arguments in the call.
  • TypeError: unsupported operand type(s) for +: 'NoneType' and 'int': you used the result of a function that printed instead of returning. See the code below.
def triple(n):
answer = n * 3
print(answer)
total = triple(4) + 1

This prints 12 and then crashes. triple prints its answer but returns None, so None + 1 is a TypeError. Fix: replace print(answer) with return answer.

Just for fun

A function walks into a café and orders a coffee. The barista hands it the cup. The function drinks it and walks out without paying.

The barista sighs: "Typical. It returned None."

Hands-on activity

Recipe functions

You need: a favourite recipe (maple taffy, pancakes, bannock, anything), paper and pencil, and a computer with Python.

  1. A recipe is like a program. Find a step that repeats or could be reused, such as "convert cups to millilitres" (1 cup is about 250 mL in Canadian recipes) or "scale an amount for more people".
  2. On paper, design two functions: one that returns a value, e.g. cups_to_ml(cups), and one procedure that prints a nicely formatted ingredient line, e.g. print_ingredient(name, amount, unit).
  3. Write both with docstrings, then use them to print the whole ingredient list for double the recipe.
  4. Explain to a family member which function returns and which prints, and why cups_to_ml must return.

What to look for: names are verbs or results in snake_case, each function has a docstring, and the returning function contains no print.

Your turn

1

Write a function square(n) that returns n times n. Call it to print the square of 12.

2

In def area(length, width): and the call area(5, 3), name the parameters and the arguments.

3

What does a function return if it has no return statement?

4

Predict the output:

def f(x):

    return x + 1

    print("done")

print(f(f(2)))

5

Write a function is_freezing(temp_c) that returns True if the temperature is 0 °C or colder.

6

Why is a docstring better than no comment at all?

7

Rename these badly named functions: x(a, b) that returns the larger of two numbers; Stuff(lst) that prints a list one item per line.

More practice: warm-up

1

Which keyword starts a function definition?

2

What must the body of a function be?

3

What symbol ends the header line?

4

True or false: a def block runs as soon as Python reads it.

5

What does return do?

More practice: on your own

1

Write c_to_f(c) that returns the Fahrenheit temperature 9c/5 + 32. What is c_to_f(-40)?

2

Write count_below(values, limit) that returns how many elements of values are less than limit.

3

Predict the output:

def mystery(a, b):

    if a > b:

        return a - b

    return b - a

print(mystery(3, 10), mystery(10, 3))

4

This program crashes with NameError. Why? Fix it.

print(greet("Noor"))

def greet(name):

    return "Hi " + name

5

Write a procedure print_receipt(items, prices) that prints each item and price on its own line, then the total. Why is it a procedure?

Challenge

1

Write is_prime(n) that returns True if the whole number n (n ≥ 2) has no divisors other than 1 and itself. Use it to print the primes below 30.

2

Write hypotenuse(a, b) without importing anything, and explain why print(hypotenuse(3, 4)) shows 5.0.

3

A function average(values) crashes on an empty list. Rewrite it so it returns None for an empty list, and explain why the caller must still check the result.

Check your understanding

Quiz

1.

In def bonus(mark, extra):, what are mark and extra?

2.

What does this print? def f(n): return n * 2 then print(f(3) + f(4))

3.

What is the main difference between return x and print(x) inside a function?

4.

A program calls area(5) but the function is def area(length, width):. What happens?

5.

Which is the best name and header for a function that returns the number of days below freezing?

6.

Where must a function's definition be, compared with the line that first calls it?

For parents and teachers

Big idea: Expectation A3.2 asks students to write subprograms (functions and procedures) that use parameter passing and appropriate scope. This lesson covers writing and calling them; the next two lessons go deeper. A4.2 (naming and internal documentation) is practised with docstrings and snake_case names.

How to help: Ask your teen to explain the flow of control diagram in their own words: where does the program start, when does it jump, and what comes back? The recipe activity works well as a conversation in the kitchen.

Common difficulties:

  • Printing inside a function instead of returning. If a result needs to be used later, it must be returned.
  • Thinking the def block runs on its own. Only a call runs it.
  • Mixing up parameters and arguments. Parameters are the names in the definition; arguments are the values in the call.
  • Putting code after return and expecting it to run.
  • Missing indentation, which causes IndentationError (a syntax error) before the program even starts.