← Teacher guide

Modules

Students import functions from a module (a separate file of related functions), see why copied code costs more to fix, then build a module of their own.

Python functions and events · Functions · about 55 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict and Run 10 min · Investigate 15 min · Modify 15 min · Make 15 min

Before class

A module is a Python file of functions that other programs can use. from shapes import square means "find the file shapes.py and bring in its square function". In the playground, + module makes a new file tab. Before class, do the Modify step yourself: move the three house functions into a module and import house.

Running the lesson

  1. Predict: the program draws a square and a triangle but never defines them. Ask where they might come from.
  2. Investigate (one bug, two copies): both programs have the same wrong turn. Fixing it means editing twice, and missing one leaves a bug. That cost is the reason modules exist.
  3. Point out that My tools works the same way as copying: each paste is a separate copy.
  4. Investigate (where does it come from?): open the shapes module from the Reference panel. Ask: what happens if main.py defines its own square after importing one?
  5. Modify: students move three functions into a module, import house, and fix the turn once.
  6. Make: a theme helps (trees, stars, buildings). Keep the drawing calls in main.py; the module only holds functions.

The hard part (on purpose)

Seeing why a module beats copying, and that a def with the same name replaces an import. Ask how many places they'd have to fix if the code were copied.

When students get stuck

What you will seeA question to askThe fix
A ModuleNotFoundError or ImportError.Is the module's file name exactly the name after from, without .py?The tab name and the import must match exactly, in lowercase.
The drawing happens twice, or as soon as the module is imported.Are there calls (not just defs) inside the module?Keep only def blocks in the module. Calls go in main.py.
An imported function behaves differently from what the module says.Is there a def with the same name in main.py?A def in main.py with the same name replaces the imported one. Rename or delete one of them.

Answers to the checks

  1. Every line to change: The walls do not close: the turn inside wall is wrong. Click every line you would have to change.
    line program_a.py:7 and program_b.py:7
    Both programs run, but each has its own copy of wall, so the same fix is needed in two places. Miss one and that program stays wrong.
  2. Count the fixes: You fix the bug in program_a.py. What happens to program_b.py?
    It still has the bug, so you fix it separately
    Each file has its own copy of wall, so each copy needs fixing. If both programs imported wall from one module, you would fix it once.
  3. Find the def: Where is square defined?
    In shapes.py, which this program imports
    The def lives in shapes.py. The import line makes it available here.
  4. Same name twice: main.py imports square, then defines its own square. What does square(80) draw?
    A circle, from main.py
    The def in main.py comes after the import, so the name square now means the new function. Python gives no warning. Use a different name, or keep one definition.
  5. Mix it up: How far does the turtle draw in total, counting only the lines (not the turns)?
    320
    square(30) draws 4 × 30 = 120 and square(50) draws 4 × 50 = 200, so 320 altogether.

Solutions

One possible solution for each task. Other correct programs are fine.

Modify

main.py
from turtle import *
from house_parts import house

house(60)
house_parts.py
from turtle import *


def wall(size):
    for i in range(4):
        forward(size)
        right(360 / 4)


def roof(size):
    left(60)
    forward(size)
    right(120)
    forward(size)
    right(120)
    forward(size)
    right(180)


def house(size):
    wall(size)
    roof(size)

Make

main.py
from turtle import *
from garden import tree, flower, fence

speed(0)
penup()
goto(-180, -80)
pendown()
fence(18)
penup()
goto(-120, -80)
pendown()
tree(60)
penup()
goto(60, -80)
pendown()
flower(25)
garden.py
from turtle import *


def tree(height):
    """A trunk and a round top."""
    setheading(90)
    pencolor("brown")
    forward(height)
    pencolor("green")
    dot(height)
    setheading(0)


def flower(size):
    """Five petals round a centre."""
    pencolor("purple")
    for i in range(5):
        circle(size / 2)
        left(72)
    dot(size / 2, "gold")


def fence(posts):
    """A row of fence posts, 20 apart."""
    setheading(0)
    pencolor("grey")
    for i in range(posts):
        left(90)
        forward(30)
        backward(30)
        right(90)
        forward(20)

Extend a street

from turtle import *
from shapes import square, triangle

for i in range(5):
    square(60 + i * 10)
    pencolor("red")
    triangle(60 + i * 10)
    pencolor("black")
    penup()
    forward(110)
    pendown()

Stretch and support

Stretch: Write a module with a docstring for each function (a first line in triple quotes). The docstring becomes the hint on the function's card in the Reference panel.

Support: Do the Modify step together on the projector, then let students make a two-function module before attempting three.

Exit ticket

Two programs each have their own copy of a draw_tree function with a bug. Why would putting draw_tree in a module be better?

Both programs would import the one function, so fixing it once in the module fixes it for both.

What each step is for

Where it leads

Next unit makes programs react to clicks and keys. Every real Python program imports modules others wrote (random, math, and libraries like Gradio). Class ideas: each student builds a module for a theme and a classmate imports it; a class town built from everyone's modules.