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

Using Built-in Functions and Modules

A3.1 A4.3About 65 minutes
Learning goals
  • I can call an existing subprogram with the right arguments and use the value it returns.
  • I can use built-in functions such as abs, round, max, min, sum and len.
  • I can import the math and random modules and use functions such as math.sqrt and random.randint.
  • I can read documentation and error messages (NameError, TypeError, AttributeError) to fix a call.

Words to know

subprogram
A named block of code that does one task and can be called from other code. Functions, procedures and methods are subprograms.
call
To run a subprogram by writing its name followed by brackets, e.g. abs(-5).
argument
A value you pass into a subprogram when you call it. In round(3.14159, 2) the arguments are 3.14159 and 2.
return value
The value a function sends back to the code that called it.
module
A file of ready-made subprograms you can import, such as math or random.
pseudo-random
Numbers made by a formula that look random. Starting the formula from the same seed gives the same sequence.
None
Python's value for "nothing". A function that does not return anything returns None.

Standing on the shoulders of other programmers

You have been using subprograms since your first program: print(), input(), len(), int(). Someone else wrote them, tested them and documented them, and you just call them. Real software is built this way. Nobody writes their own square-root code; they use one that thousands of people have already checked.

The curriculum asks you to use existing subprograms, giving as examples a random number generator, substring (which you met in Strings as Sequences) and absolute value. This lesson shows how to call them well, how to find new ones, and how to read the error messages when a call goes wrong.

What happens in a call

In d = abs(-7.6):

  • abs is the name of the subprogram.
  • -7.6 is the argument: the input you hand it.
  • The function runs and returns a value, 7.6.
  • The whole call abs(-7.6) is replaced by the returned value, so d = 7.6.

Because a call becomes a value, you can use it anywhere a value fits: inside a bigger expression, as an argument to another call, or in an if.

arguments-7.6abs(someone else's code)return value7.6d = abs(-7.6)the call is replaced by the value it returns, so d is 7.6
A function works like a machine: arguments go in, a return value comes out. You do not need to see the code inside to use it; you only need to know what goes in and what comes out.

Built-in functions you should know

These are always available, with no import:

  • abs(x): absolute value (distance from 0). abs(-11) is 11.
  • round(x, n): x rounded to n decimal places. With one argument it rounds to a whole number.
  • max(...), min(...): the largest / smallest of a list or of several arguments.
  • sum(a): the total of a list of numbers.
  • len(x): the length of a list or string.
  • int(), float(), str(): convert between types.
temps = [-4, 3, -11, 7]
print(abs(-11))
print(round(7.4567, 2))
print(max(temps), min(temps))
print(sum(temps))
print(len(temps))
print(round(sum(temps) / len(temps), 1))

Output: 11, 7.46, 7 -11, -5, 4, -1.2. The last line nests three calls: sum and len run first, then the division, then round.

A rounding surprise

Python's round() sends an exact half to the nearest even number: round(2.5) is 2 and round(3.5) is 4. This is called banker's rounding. It keeps totals fair when many halves are rounded. Also, round(2.675, 2) gives 2.67, because 2.675 cannot be stored exactly in binary (you saw how numbers are stored in Programming Basics).

Modules: importing more tools

Python keeps less common tools in modules. Write import module_name at the top of the program, then call its functions with a dot: math.sqrt(16).

  • math: math.sqrt(x), math.pi, math.floor(x) (round down), math.ceil(x) (round up), math.hypot(a, b) (the hypotenuse, √(a² + b²)).
  • random: random.randint(a, b) gives a whole number from a to b, including both a and b; random.random() gives a float from 0 up to (not including) 1; random.choice(lst) picks one element; random.shuffle(lst) mixes a list in place; random.seed(n) makes the sequence repeatable.
import mathmath.sqrt(x)square rootmath.pi3.14159...math.floor(x)round downmath.ceil(x)round upmath.hypot(a, b)hypotenuseimport randomrandom.randint(a, b)whole number from a to brandom.random()float from 0 up to 1random.choice(lst)one random elementrandom.shuffle(lst)mixes the list in placerandom.seed(n)makes runs repeatable
Two modules and some of their functions. After import math, you reach each tool with the module name and a dot.
Worked example

Example 1: A ramp and granola bar boxes

(a) A ramp rises 1.5 m over a horizontal run of 6.0 m. How long is the ramp surface, to two decimals? (b) Each box holds 12 granola bars. How many boxes are needed for 53 bars, and how many boxes can be filled completely?

  1. (a) The ramp is the hypotenuse of a right triangle: √(1.5² + 6.0²) = √(2.25 + 36) = √38.25 ≈ 6.18 m. Use math.sqrt or math.hypot.
  2. (b) 53 ÷ 12 ≈ 4.42. You need to round up to hold every bar: math.ceil gives 5. Full boxes need round down: math.floor gives 4.
  3. Code: import math rise = 1.5 run = 6.0 ramp = math.sqrt(rise * rise + run * run) print(round(ramp, 2)) print(round(math.hypot(rise, run), 2)) boxes = math.ceil(53 / 12) print(boxes, math.floor(53 / 12))

Output: 6.18, 6.18, 5 4.

Worked example

Example 2: Simulating 1000 rolls of two dice

Use random.randint and a list of counters to estimate how often each total from 2 to 12 comes up when two dice are rolled.

  1. A list counts of 13 zeros gives one counter for each possible total. The total itself is used as the index: counts[total] += 1. (Indexes 0 and 1 are never used.)
  2. random.randint(1, 6) includes both 1 and 6, like a real die.
  3. Code: import random counts = [0] * 13 # indexes 0..12; we use 2..12 for roll in range(1000):     total = random.randint(1, 6) + random.randint(1, 6)     counts[total] += 1 for t in range(2, 13):     print(t, counts[t])
  4. The numbers change on every run. In 36 equally likely pairs, 6 make a total of 7, so you should see about 1000 × 6/36 ≈ 167 sevens, and only about 28 twos and 28 twelves.

A table of totals 2 to 12 with the most near 7. Results differ each run because the numbers are random.

import random
random.seed(7)
snacks = ["apple", "trail mix", "bannock", "cheese"]
print(random.choice(snacks))
random.shuffle(snacks)
print(snacks)

With random.seed(7) this prints the same snack and the same shuffled order every time you run it on the same version of Python. Seeds are useful for testing random programs. Remove the seed line for real use.

Return values vs. side effects

Some subprograms return a useful value (abs, len, round). Others do something instead, a side effect, and return None: print shows text, list.sort() and random.shuffle() rearrange a list in place. (Some languages call a subprogram that returns nothing a procedure.) A common bug is to save the result of one of these:

x = print("Hi")
print(x)
a = [3, 1, 2]
b = a.sort()
print(a, b)

Output: Hi, then None, then [1, 2, 3] None. a.sort() sorted a in place and returned None, so b is None. If you want a new sorted list, use sorted(a).

Reading the documentation and the error messages

  • In the Python shell, help(round) prints the documentation. The official reference is at docs.python.org (look for Built-in Functions and the math and random modules).
  • The first line of the help is the signature, e.g. round(number, ndigits=None): it lists the parameters and shows that ndigits is optional.

When a call goes wrong, the last line of the traceback tells you what kind of mistake you made:

Error message (last line)What it meansFix
NameError: name 'math' is not definedYou used a module without importing it.Add import math at the top.
AttributeError: module 'math' has no attribute 'squareroot'That function name does not exist in the module.Check the docs: it is math.sqrt.
TypeError: abs() takes exactly one argument (2 given)Wrong number of arguments.Pass exactly what the signature asks for.
ValueError: math domain errorThe argument is the right type but an impossible value, e.g. math.sqrt(-4).Check the value before calling.
Four common errors when calling existing subprograms. Recent versions of Python add hints such as "Did you forget to import 'math'?".
Just for fun

Ask Python for a random number between 1 and 10 three times and you might get 4, 4, 4. That is not broken; real randomness repeats more than people expect. Some music apps have reportedly made their "shuffle" less random on purpose, because listeners complained that true random played the same artist twice in a row too often.

Hands-on activity

Is the die fair?

You need: one real die (from a board game), a pencil and paper, and a computer with Python.

  1. Roll the real die 60 times and tally how many times each face (1 to 6) appears.
  2. Write a program that does the same with random.randint(1, 6) 60 times, storing the tallies in counts = [0] * 7 and using the roll as the index.
  3. Run it for 600 and 60 000 rolls. Print each count and its percentage with round(100 * counts[f] / n, 1).
  4. Compare: Which results are closest to 16.7% each? (With more rolls, the percentages usually get closer to 1/6.)
  5. Try to cause and then fix three errors on purpose: remove import random, misspell randint as randInt, and call random.randint(6). Write down the last line of each error message.

What to look for: the student explains that a bigger sample gives percentages closer to 16.7%, and can name the error type for each mistake.

Your turn

1

What is abs(3 - 10)?

2

What is round(18.4567, 1)?

3

Write a line that prints the highest mark in the list marks using a built-in function.

4

Which line must come first before you can use math.sqrt?

5

Can random.randint(1, 6) return 6? Can random.random() return 1?

6

Write one line that sets pick to a random name from the list names.

7

What does print(round(2.5), round(3.5)) show?

More practice: warm-up

1

What is the return value of len("Yukon")?

2

What is min(4, -2, 9)?

3

What is math.floor(7.9)?

4

What is math.ceil(7.1)?

5

What does a function that does not return anything give back?

More practice: on your own

1

Predict the output:

import math

print(math.sqrt(abs(-49)) + max(2, 5))

2

Write a program that prints a random temperature from −30 to 5 (whole degrees), then prints "Cold!" if it is below −15.

3

A program says TypeError: round() takes at most 2 arguments (3 given). What went wrong?

4

Why is b = a.sort() almost always a bug? Write the correct version.

5

Write code that picks a random index of a list a (not a random element). Which bound is easy to get wrong?

Challenge

1

Write a program that simulates flipping a coin 100 times with random.randint(0, 1) and prints the longest streak of heads (1s) in a row.

2

Use the distance formula d = √((x₂ − x₁)² + (y₂ − y₁)²) with math functions to find the distance between (−2, 3) and (4, −5).

3

You are given import random and random.seed(42). Explain why a test plan for a dice game might use a seed, and why the final game should not.

Check your understanding

Quiz

1.

In x = round(5.678, 1), what is the return value?

2.

Which call can return any whole number from 1 to 10, including both 1 and 10?

3.

A program says NameError: name 'random' is not defined. What is the most likely fix?

4.

What does print(sum([2, 4, 6]) / len([2, 4, 6])) show?

5.

What is stored in y after y = print("hello")?

6.

math.ceil(53 / 12) gives 5. What is it used for in the granola bar example?

For parents and teachers

Big idea: A3.1 asks students to use existing subprograms, with the examples random number generator, substring and absolute value. A4.3 asks them to interpret error messages; the table of NameError, AttributeError, TypeError and ValueError gives them a routine.

How to help: Do the dice activity together; it is quick and makes probability and code meet. When your teen hits an error, ask them to read the last line aloud and say which type of mistake it is before they change anything.

Common difficulties:

  • Forgetting import, or writing sqrt(9) instead of math.sqrt(9) after import math.
  • Off-by-one with randint: random.randint(0, len(a)) can return an index that is out of bounds.
  • Saving the result of an in-place method (b = a.sort()), which gives None.
  • Surprise at round(2.5) giving 2. This is correct Python behaviour, not a bug.