Chapter 2 · Decide, repeat, reuse
Modules and programs
Step 1 of 21 · Concept
Some functions are always there
In this lesson you use Python's ready-made functions and modules, and split a program into files.
These built-in functions are always there:
| call | gives |
|---|---|
len("Ada") | 3 |
abs(-3) | 3 |
round(2.7) | 3 |
min(4, 9) | 4 |
max(4, 9) | 9 |
type(2.5) | <class 'float'> |
round(3.14159, 2) keeps two decimals: 3.14. But round(5.0, 2) shows 5.0, not 5.00; :.2f always shows
two (lesson 4).
Step 2 of 21 · Quiz
Predict the numbers
Type exactly what this program prints.
print(round(2.5), round(3.5), abs(-3), max(4, 9))
print(round(3.14159, 2), round(5.0, 2))
Step 3 of 21 · Demo
See it run
Run it and compare with your answer.
Step 4 of 21 · Concept
import loads a module
import math
from math import sqrt
A module is a set of names you load with import. It is one of Python's own (math is written in C), or a
.py file of yours.
import math binds math to the module. A dot reaches its names: math.sqrt(16) is 4.0, math.floor(2.7)
is 2. from math import sqrt binds sqrt itself.
Step 5 of 21 · Try it
Try it: fix the import
Run it: line 1 stops with ModuleNotFoundError: No module named 'maths'. Fix the name and run it again.
Now print(sqrt(9)) stops with a NameError: import math binds only math. Add the line
from math import sqrt, and the program prints four values.
The module is math, not maths. The from line goes under the import line.
Step 6 of 21 · Concept
random, with a seed
import random
random.seed(42)
print(random.randint(1, 6))
random.randint(1, 6)gives a whole number from 1 to 6. Both ends are included, unlikerange.- Python computes the numbers from a hidden starting number;
random.seed(42)sets it. - Without a seed it changes every run. The same seed gives the same numbers on every run.
Every program in this course seeds random, so its output is the same each time.
Step 7 of 21 · Demo
Roll eight dice
Run it, then run it again: the same eight rolls, because of the seed.
Step 8 of 21 · Exercise
Your turn: a ladder
A ladder stands out metres from a wall and reaches up metres high. Its length is the square root of
out ** 2 + up ** 2.
Make ladder(out, up) return it, rounded to 2 decimals. The program must print:
5.0
5.39
Two steps: the square root, then the rounding. 5.0 has no second decimal, so it prints as 5.0.
math.sqrt(out ** 2 + up ** 2) is the length. Pass it to round with 2.
length = math.sqrt(out ** 2 + up ** 2)
Step 9 of 21 · Concept
Your file is a module too
shapes.py:
def area(w, h):
return w * h
main.py:
import shapes
print(shapes.area(3, 4))
Any .py file beside main.py is a module: import shapes loads shapes.py. Python runs the file once, at
its first import, and binds the name shapes to the module. Its names come after a dot, as math's do.
main.py is a module too: that is why its frame is called <module>.
Step 10 of 21 · Demo
Two files, one program
This shapes.py also prints a line, and main.py imports it twice. Run it: the line shows once. Then open
shapes.py in its tab.
Step 11 of 21 · Try it
Try it: a mistake in a module
Python reads shapes.py only when the import runs. So Start prints first, and then the traceback names
shapes.py, line 1:
SyntaxError: expected ':'
Fix shapes.py. Then the program prints Start and 12.
A def line ends with a :.
Step 12 of 21 · Demo
A file named like a module hides it
import random finds this folder's own random.py first, and Python's stays hidden. Run it:
my random.py prints, then Python stops with
AttributeError: module 'random' has no attribute 'seed' (consider renaming '.../random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module).
Never name a file like a module you use.
Step 13 of 21 · Concept
A test block runs only in the file you run
def area(w, h):
return w * h
if __name__ == "__main__":
print("Test:", area(2, 3))
Each module has a name __name__. In the file you run, it is "__main__". In an imported file, it is the
module's name, such as "shapes".
So the block under if __name__ == "__main__": runs when you run the file, and not when it is imported. A module
keeps its own tests there.
Step 14 of 21 · Quiz
What prints on import?
main.py imports shapes.py. What does Run print? This is shapes.py:
def area(w, h):
return w * h
if __name__ == "__main__":
print("Test:", area(2, 3))
And this is main.py:
import shapes
print("Area:", shapes.area(3, 4))
Step 15 of 21 · Demo
The Terminal sees the same folder
Run it: only Area: 12. Then choose Open in the terminal in the ⋯ menu, and type:
ls: it lists the block's two files.cat shapes.py: it shows one of them.python3 shapes.py: nowshapes.pyis the file you run, soTest: 6prints.python3 main.py: what Run does.
Step 16 of 21 · Exercise
Your turn: a module of your own
main.py is ready. In money.py, write price_label(amount), which returns the text Price: and the amount
with two decimals. The program must print:
Price: 3.50
Price: 12.00
Until money.py has a def price_label, main.py stops with
AttributeError: module 'money' has no attribute 'price_label'.
def price_label(amount): returns an f-string. Two decimals are {amount:.2f} (lesson 4).
return f"Price: {amount:.2f}"
Step 17 of 21 · Concept
A folder of modules is a package
A folder of modules is a package. Its file __init__.py marks it as one. It can be empty, or hold a docstring only.
from app.prices import total reads: from the module prices in the package app, bind the name total.
Step 18 of 21 · Demo
A package at work
A project block shows its folders as a tree. Run it: main.py uses total from app/prices.py.
Step 19 of 21 · Check yourself
Check yourself: dice in two files
No shape this time.
- In
dice.py, writeroll_two(), which returns the sum of tworandom.randint(1, 6)rolls. - In
main.py, seedrandomwith 42, then print five rounds ofdice.roll_two()and their total.
The seed in main.py works for dice.py too: both import the one random module. The output must be exactly:
Round 1: 7
Round 2: 7
Round 3: 5
Round 4: 4
Round 5: 7
Total: 30
Each file imports what it uses: dice.py needs random, and main.py needs both random and dice.
Step 20 of 21 · Challenge · optional
Challenge: rock, paper, scissors
Optional.
Play three rounds. In each, pick your move, then the computer's, at random from moves. Print the result with
beats.
The output must be exactly:
paper vs rock: you win
paper vs scissors: you lose
rock vs rock: draw
random.choice(moves) picks one of the three moves. Pick yours first, then the computer's, in every round.
In a for loop of 3 rounds: two random.choice calls, then if beats(me, them):, elif beats(them, me):, else:.
me = random.choice(moves)
them = random.choice(moves)
Step 21 of 21 · Recap
Recap
len,abs,round,min,maxandtypeneed noimport;round(2.5)is2.import mathbindsmathto a module:math.sqrt(16).from math import sqrtbindssqrt.random.seed(42)makesrandom.randint(1, 6)give the same rolls on every run.- Your own
shapes.pyis a module: it runs once, at its firstimport. if __name__ == "__main__":holds what runs only when you run that file.
Next: lesson 9 opens text up: positions, slices and methods.
Review
2 questions from this lesson, in a new order each time. Answer from memory: 2 of 2 right on the first try passes. On a day after you finish the lesson, a pass earns 15 XP.
The review needs JavaScript.
print(round(2.5), round(3.5), abs(-3), max(4, 9))
print(round(3.14159, 2), round(5.0, 2))
import maths
print(math.sqrt(16))
print(sqrt(9))
print(math.floor(2.7))
print(math.pi)
import random
random.seed(42)
for i in range(8):
print(random.randint(1, 6), end=" ")
print()
import math
def ladder(out, up):
return 0
print(ladder(3, 4))
print(ladder(2, 5))
import shapes
import shapes
print("Area:", shapes.area(3, 4))
print("Start")
import shapes
print(shapes.area(3, 4))
import random
random.seed(1)
print(random.randint(1, 6))
import shapes
print("Area:", shapes.area(3, 4))
import money
print(money.price_label(3.5))
print(money.price_label(12))
from app.prices import total
print(f"Total: {total(2.5, 4):.2f}")
# seed random with 42, then five rounds
# of dice.roll_two() and the total
import random
def beats(a, b):
"""True when move a beats move b."""
if a == "rock":
return b == "scissors"
elif a == "paper":
return b == "rock"
else:
return b == "paper"
moves = ["rock", "paper", "scissors"] # a list: lesson 10
random.seed(7)