Writing Functions

Overview

Teaching: 15 min
Exercises: 20 min
Questions
  • How can I make code more readable?

  • How can I make code reusable?

Objectives
  • Write a function taking a fixed number of parameters and having a single point of return.

  • Write functions whose parameters have default values.

  • Write functions with multiple points of return.

  • Write functions that return multiple values.

  • Extract functions from longer programs.

  • Trace the execution of nested non-recursive function calls.

  • Correctly identify the scope of variables.

Break programs down into functions.

Define a function using def with a name, parameters, and a block of code.

def print_greeting():
    print('Hello!')

Arguments in call are matched to parameters in definition.

def print_date(year, month, day):
    joined = str(year) + '/' + str(month) + '/' + str(day)
    print(joined)

print_date(1871, 3, 19)
1871/3/19

Functions may return a result to their caller using return.

def average(values):
    if len(values) == 0:
        return None
    return sum(values) / len(values)
a = average([1, 3, 4])
print('average of actual values:', a)
2.6666666666666665
print('average of empty list:', average([]))
None
result = print_date(1871, 3, 19)
print('result of call is:', result)
1871/3/19
result of call is: None

Can specify default values for parameters.

def sum(values, scale=1.0):
    result = 0.0
    for v in values:
        result += v * scale
    return result

print('sum with default:', sum([1, 2, 3]))
print('sum with factor:', sum([1, 2, 3], 0.5))
sum with default: 6.0
sum with factor: 3.0

Can pass parameters by name.

print('out of order:', sum(scale=0.25, values=[1, 2, 3]))
out of order: 1.5

Functions can take a variable number of arguments.

def total(scale, *args):
    result = 0.0
    for a in args:
        result += a * scale
    return result

print('with one value:', total(0.5, 1))
print('with two values:', total(0.5, 1, 3))
with one value: 0.5
with two values: 2.0

Functions can return multiple values.

red, green, blue = 10, 50, 180

def order(a, b):
    if a < b:
        return a, b
    else:
        return b, a

low, high = order(10, 5)
print('order(10, 5):', low, high)
order(10, 5): 5 10

Encapsulation

Fill in the blanks to create a function that takes a single filename as an argument, loads the data in the file named by the argument, and returns the minimum value in that data.

import pandas

def min_in_data(____):
    data = ____
    return ____

Find the First

Fill in the blanks to create a function that takes a list of numbers as an argument and returns the first negative value in the list. What does your function do if the list is empty?

def first_negative(values):
    for v in ____:
        if ____:
            return ____

Running Sum

Write a function that calculates the running sum of any number of input arguments, returning the result as a list. For example:

  • running(1, 2) => [1, 3]
  • running(-5, 2, 7) => [-5, -3, 4]

What should running() return, and why?

Extracting Functions

People often create functions by extracting pieces of code from scripts they’ve written. Re-write the short program below to have one or more functions so that no single piece of code is more than ten lines long. Do you find the result easier to understand?

# Report the number of lines in each chapter in a text file.
# A chapter heading has '##' in the first two columns.
# Blank lines are *not* counted in totals.

reader = open('thesis.txt', 'r')
current_title = None
current_count = None
for line in reader:
    line = line.strip()
    if not line:
        pass
    elif line.startswith('##'):
        if current_title is None:
            current_title = line
	    current_count = 0
        else:
            print(current_title, current_count)
            current_title = line
            current_count = 0
    else:
        current_count = current_count + 1

if current_title is not None:
    print(current_title, current_count)

Key Points

  • Use def to define a new function.

  • Give parameters default values to make use easier and intent clearer.

  • Use *args to handle variable-length parameter lists.

  • Use return at any point to return values.

  • Turn repeated or deeply-nested pieces of code into functions.

  • Functions temporarily store values on a call stack.