A. Programming Concepts and Skills · Arrays and SubprogramsUsing 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.
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.
Two modules and some of their functions. After import math, you reach each tool with the module name and a dot.Worked exampleExample 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?
- (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. - (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. - 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))
Worked exampleExample 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.
- 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.) random.randint(1, 6) includes both 1 and 6, like a real die.- 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]) - 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 means | Fix |
|---|
| NameError: name 'math' is not defined | You 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 error | The 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 funAsk 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 activityIs the die fair?
You need: one real die (from a board game), a pencil and paper, and a computer with Python.
- Roll the real die 60 times and tally how many times each face (1 to 6) appears.
- 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. - Run it for 600 and 60 000 rolls. Print each count and its percentage with
round(100 * counts[f] / n, 1). - Compare: Which results are closest to 16.7% each? (With more rolls, the percentages usually get closer to 1/6.)
- 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
7. 3 − 10 = −7, and the absolute value is 7.
2What is round(18.4567, 1)?
3Write a line that prints the highest mark in the list marks using a built-in function.
4Which line must come first before you can use math.sqrt?
5Can random.randint(1, 6) return 6? Can random.random() return 1?
Yes, randint includes both ends. No, random() is always less than 1.
6Write one line that sets pick to a random name from the list names.
pick = random.choice(names) (after import random).
7What does print(round(2.5), round(3.5)) show?
2 4. Halves round to the nearest even whole number.
More practice: warm-up
1What is the return value of len("Yukon")?
5What does a function that does not return anything give back?
More practice: on your own
1Predict the output:
import math
print(math.sqrt(abs(-49)) + max(2, 5))
12.0. abs(−49) = 49, √49 = 7.0, max is 5, so 7.0 + 5 = 12.0 (sqrt returns a float).
2Write a program that prints a random temperature from −30 to 5 (whole degrees), then prints "Cold!" if it is below −15.
import random
t = random.randint(-30, 5)
print(t)
if t < -15:
print("Cold!")
3A program says TypeError: round() takes at most 2 arguments (3 given). What went wrong?
round was called with three arguments, but its signature allows only number and ndigits. Remove the extra argument.
4Why is b = a.sort() almost always a bug? Write the correct version.
sort() sorts in place and returns None, so b becomes None. Use a.sort() alone, or b = sorted(a) to get a new sorted list.
5Write code that picks a random index of a list a (not a random element). Which bound is easy to get wrong?
i = random.randint(0, len(a) - 1). The upper bound must be len(a) − 1, because randint includes its upper argument.
Challenge
1Write 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.
import random
flips = []
for i in range(100):
flips.append(random.randint(0, 1))
longest = 0
current = 0
for f in flips:
if f == 1:
current += 1
if current > longest:
longest = current
else:
current = 0
print(longest)
current counts the streak in progress and resets at every tail; longest is a max tracker. Typical answers are around 5 to 7.
2Use the distance formula d = √((x₂ − x₁)² + (y₂ − y₁)²) with math functions to find the distance between (−2, 3) and (4, −5).
math.sqrt(pow(4 - -2, 2) + pow(-5 - 3, 2)) = √(36 + 64) = √100 = 10.0. (Or math.hypot(6, -8).)
3You 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.
With a fixed seed, the "random" numbers are the same on every run, so you can write down the expected output and compare it with the actual output. A real game needs different rolls each time, so the seed is removed (Python then seeds from the system time or the operating system).
Check your understandingQuiz
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 teachersBig 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.