7.4. Tuples and Functions#
import sys
from pathlib import Path
# Find project root by looking for _config.yml
current = Path.cwd()
for parent in [current, *current.parents]:
if (parent / '_config.yml').exists():
project_root = parent
break
else:
project_root = Path.cwd().parent.parent
# Add project root to path
sys.path.insert(0, str(project_root))
# Import shared teaching helpers and cell magics
from shared import thinkpython, diagram, jupyturtle, structshape
from shared.download import download
7.4.1. Tuples as Return Values#
A function returns one object, but that object can be a tuple. Returning a tuple is a common way to provide multiple results.
For example, a scheduling system may need to convert a total number of minutes into hours and minutes.
The built-in function divmod (// and %) takes two arguments and returns a tuple with the quotient and remainder.
divmod(135, 60) # 135 minutes → (2 hours, 15 minutes)
(2, 15)
We can use tuple assignment to store the hours and minutes in separate variables.
hours, minutes = divmod(135, 60)
hours
2
minutes
15
Here is a simple function that returns both the minimum and maximum from a list — useful for summarizing a range of values, such as daily sales figures.
def min_max(t):
return min(t), max(t)
min and max are built-in functions that find the smallest and largest elements of a sequence.
min_max computes both and returns them as a tuple.
min_max([8500, 12400, 7200, 9900]) # daily sales figures
(7200, 12400)
We can unpack the result like this:
low, high = min_max([8500, 12400, 7200, 9900])
low, high
(7200, 12400)
### Exercise: Tuples as Return Values
# Write a function called `stats` that takes a list of numbers and returns
# a tuple containing (min, max, sum, mean) of the list.
# Test it with [10, 20, 30, 40, 50] and unpack the result into four variables.
### Your code starts here.
### Your code ends here.
10 50 150 30.0
7.4.2. Argument Packing#
Functions can take a variable number of arguments.
A parameter name that begins with * packs extra arguments into a tuple.
The following function (pretending we don’t have a built-in for it) takes any number of arguments and computes their arithmetic mean.
def mean(*args): # variable-length argument list
return sum(args) / len(args)
The parameter name can be anything, but args is conventional.
Here we call it with three employee performance scores:
mean(8500, 12400, 7200, 9900) # average of four daily sales figures
9500.0
If you have a sequence of values and want to pass them as separate arguments, use * to unpack the sequence.
For example, divmod takes exactly two arguments - if you pass a tuple, it counts as a single argument and raises an error.
%%expect TypeError
t = (135, 60)
divmod(t)
TypeError: divmod expected 2 arguments, got 1
Even though the tuple contains two elements, it is still one argument. If you unpack it, the two elements are passed separately.
divmod(*t)
(2, 15)
Packing and unpacking are handy when you want to adapt an existing function. For example, this function takes any number of arguments, removes the lowest and highest, and computes the mean of the rest.
def trimmed_mean(*args):
low, high = min_max(args)
trimmed = list(args) # convert to a list for mutability
trimmed.remove(low)
trimmed.remove(high)
return mean(*trimmed)
First it uses min_max to find the lowest and highest values.
Then it converts args to a list so it can use remove.
Finally it unpacks the trimmed list so the elements are passed to mean as separate arguments.
Here is an example using judge scores, where one score is unusually low:
mean(8.5, 9.2, 8.8, 4.5) # raw mean including the outlier
7.75
trimmed_mean(8.5, 9.2, 8.8, 4.5) # mean after dropping lowest (4.5) and highest (9.2)
8.65
You can also unpack sequences to build new tuples (or lists) without using +.
For example, merging two quarterly sales tuples into a single half-year tuple:
q1 = (112, 98, 135) # monthly sales for Q1
q2 = (144, 101, 129) # monthly sales for Q2
h1 = (*q1, *q2) # combined first-half data
h1
(112, 98, 135, 144, 101, 129)
This kind of trimmed mean is used in sports with subjective judging (like diving and gymnastics) to reduce the influence of outlier scores.
### Exercise: When to Use Tuples
# For each scenario below, decide whether a tuple or a list is more appropriate
# and implement it:
# 1. Store the (latitude, longitude) coordinates of a fixed location: 38.9, -77.0
# 2. Build a collection of city names that will have cities added to it over time.
# Start with ['Paris', 'Tokyo'] and append 'Nairobi'.
# 3. Use a (month, day) tuple as a key in a dictionary to store holiday names.
# Add entries for (1,1)->'New Year' and (7,4)->'Independence Day'.
# Print the holiday for July 4th.
### Your code starts here.
### Your code ends here.
(38.9, -77.0)
['Paris', 'Tokyo', 'Nairobi']
Independence Day