← Teacher guides

Teacher guide: Python functions and events

Write your own functions, then use them to make a button and a game.

Open the student course

Each lesson works two ways. Students can work through the online tutorial at their own pace (it checks their answers and saves their progress in their browser), or you can teach it to the whole class from the slides, then send students into the tutorial for the Modify and Make steps.

Every lesson guide has plain-language notes, the answers to every check, a solution for every task, and slides and a worksheet for Waypoints Prepare. These guide pages are not linked from student pages, but they are not secret either: keep printed Teacher editions for answers you do not want students to find.

Whole-course cheat sheet: Open to print (every command, grouped by unit: a handout for the final challenge)

Start from a working program

Read a longer program and change it without breaking it.

Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown

Functions

Name steps, give them inputs and outputs, and keep them in modules.

Functions in 5 minutes (read before teaching this unit)

The idea in plain words

A function is a named set of steps. def square(): teaches Python a new word, square, and the indented lines say what it means. Writing the def does nothing on its own; the steps run when you call it: square().

A parameter is an input: def square(size): lets each call choose, square(50) or square(150). A function can also return an answer: def metres(m): return m * 20 gives back a number other code can use, like forward(metres(5)). A module is a file of related functions that other programs import.

Why programmers use them

  • Write once, use many times. Three squares are three calls, not three copies.
  • Fix once. A change inside the function updates every call. With copies, every copy needs the same fix, and missing one leaves a bug.
  • Build big from small. Small tested pieces (a wall, a roof) combine into bigger ones (a house, a street).
  • Share. Modules let one person's functions be used by everyone, which is how Python's libraries work.

An everyday picture, and where it breaks

A function is a recipe card. Writing the card does not cook anything; following it (calling) does. A parameter is "serves 4" on the card: the same recipe for a different amount. return is handing the finished dish back to whoever asked for it.

Where it breaks: print is like showing someone a photo of the dish. They can see it, but they cannot eat it. A function that prints instead of returning gives nothing back, which is why the Returns lesson's bug stops with an error.

Try it yourself (5 minutes)

  1. In the playground, write def square(): with a loop of four forward(100) and right(90) under it. Run it: nothing is drawn.
  2. Add square() at the bottom (not indented). Now a square appears.
  3. Change the def to def square(size):, use forward(size), and call square(50) then square(100).

Questions students ask

  • "Why doesn't my def draw anything?" It only describes the steps. Call it by name with brackets.
  • "What's the difference between a parameter and an argument?" The parameter is the name in the def (size); the argument is the value in the call (50).
  • "When do I use return instead of print?" When another part of the program needs the answer. Print is only for people to read.

How it connects

Every later lesson is built from functions: event handlers in Interaction, draw_button and inside in the ui module, and every part of the final game.

Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown

Interaction

Events, and a button built from scratch.

Events and buttons in 5 minutes (read before teaching this unit)

The idea in plain words

Until now programs ran top to bottom and stopped. Event-driven programs set things up, then wait. When something happens (a click, a key, a timer), they run a function. onscreenclick(stamp) means "when the picture is clicked, run stamp". The function handed over is called a callback. mainloop() keeps the program waiting until you press Stop.

A button is three things: a rectangle drawn on screen, a label, and a hit test, the check that a click landed inside the rectangle.

Why programmers use them

Every app works this way: it waits for you, then reacts. Building a button by hand shows what tools like Gradio and every phone app do behind the scenes. The visible button is the small part; drawing it, checking the click and updating the screen are the rest.

An everyday picture, and where it breaks

A callback is like leaving your phone number with a shop: "call me when it arrives". You do not keep asking; they call you.

Where it breaks: you give them your number, not a phone call. onscreenclick(stamp) hands over the name; onscreenclick(stamp()) with brackets calls the function immediately, once, which is the classic bug.

Try it yourself (5 minutes)

  1. Run the stamp program from the Events lesson and click around the picture. Press Stop.
  2. Change dot(30, "orange") to a different size and colour.
  3. In the Build a button lesson, click inside and outside the button and watch what is printed.

Questions students ask

  • "Why doesn't the program end?" mainloop() keeps it waiting for events. Press Stop to end it.
  • "Why don't my keys work?" Click the picture first, so it is listening for keys.
  • "What is global for?" A function that changes a variable made outside it, like a score, needs global score as its first line.

How it connects

The final challenge is an event-driven game: a timer moves the turtle, clicks catch it, and buttons start the game and buy upgrades.

Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown

Final challenge: Catch the turtle

Build a game that uses everything, then add power-ups. Two optional lessons go further.

Games and apps in 5 minutes (read before teaching this unit)

The idea in plain words

A game (or an app) is three things working together:

  • Data: values that describe what is happening now (score, lives, where the turtle is, whether it is showing).
  • Rules: what each event means (a click on the turtle scores a point; a miss loses a life).
  • A loop: a timer that keeps things moving (the turtle hops every second; the clock ticks down).

True and False are values a variable can hold to remember something that is either so or not: showing = True while the turtle is on screen.

Why it matters

The challenge uses everything from the course in one program, so students see that the pieces fit together. It also previews both directions they can take next: user interface (buttons, status bars, control panels, towards Gradio and web pages) and games (screens, levels, movement, towards MakeCode Arcade and microStudio).

An everyday picture, and where it breaks

A board game: the board and pieces are the data, the rulebook is the rules, and taking turns is the loop.

Where it breaks: in a board game, players move the pieces. In a program, the loop and the events change the data, and the screen is redrawn to show it. If the data changes but nothing redraws, the player never sees it.

Try it yourself (5 minutes)

  1. Open Catch the turtle, go to Milestone 3 and paste in the solution from the teacher guide. Press Start and play one round.
  2. In the code, change xs and ys to a path of your own and play again.
  3. Change 700 in ontimer(hide, 700) to 400. The turtle hides sooner: a rule changed.

Questions students ask

  • "Why does my score not change?" The function that changes it needs the variable in its global line.
  • "Why is True written with a capital?" That is how Python spells it. true is not the same.
  • "Can I make my own game?" Yes: the Make steps are open, and the optional lessons go further.

How it connects

Finishing Catch the turtle and Power-ups marks the course Challenge complete. Control panel leads towards apps (Gradio, web pages); Game levels leads towards games (MakeCode Arcade, microStudio).

Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown

Open projects

Self-paced briefs students can pick up after the lesson named on each. Students tick their own milestones and claim a badge; the page lights the skills their code uses. Badges stay in the student's browser: ask them to press Show your teacher. Open the projects page

A street of your own (after turtle-parameters; a function with parameters, a list ([1, 2]), for item in a list)

Draw a street: houses, trees, shops or anything else, of different sizes and colours, along one line. Each kind of thing is drawn by a function you write once and call many times.

Milestones:

  • It runs and draws at least four things along a street.
  • Each kind of thing is drawn by my own function with parameters (where, how big, what colour).
  • A list says what goes on the street, and a loop draws it.

The list can hold sizes, x positions or colours; any of these counts. Students who write one long program with no functions have met the goal of a picture but not the brief: point them at the milestone about calling one function many times.

One possible solution
from turtle import *

speed(0)


def house(x, size, colour):
    penup()
    goto(x, -60)
    pendown()
    fillcolor(colour)
    begin_fill()
    for side in range(4):
        forward(size)
        left(90)
    end_fill()
    fillcolor("brown")
    begin_fill()
    goto(x, -60 + size)
    goto(x + size / 2, -60 + size * 1.5)
    goto(x + size, -60 + size)
    goto(x, -60 + size)
    end_fill()


def tree(x, size):
    penup()
    goto(x, -60)
    pendown()
    fillcolor("sienna")
    begin_fill()
    for side in range(2):
        forward(size / 4)
        left(90)
        forward(size / 2)
        left(90)
    end_fill()
    penup()
    goto(x + size / 8, -60 + size / 2)
    pendown()
    fillcolor("green")
    begin_fill()
    circle(size / 3)
    end_fill()


street = [("house", 50, "lightblue"), ("tree", 70, ""), ("house", 70, "pink"), ("house", 40, "khaki"), ("tree", 60, "")]
x = -230
for thing in street:
    if thing[0] == "house":
        house(x, thing[1], thing[2])
    else:
        tree(x, thing[1])
    x = x + thing[1] + 25
hideturtle()
Chart your data (after turtle-decide; a list ([1, 2]), for item in a list, return, if)

Choose something you can count (your week's screen time, the class's favourite fruits, rainfall) and draw it as a bar chart. A function decides each bar's colour from its value, so big and small values look different.

Milestones:

  • It draws one bar per value in my list, with heights from the data.
  • My own function returns a colour, picked with an if, and the bars use it.
  • I changed a value in the list and the chart changed with it.

Real data makes this stick: let students collect a small set first (five to eight numbers). write() is a recipe from Events; students who reach for it early can copy it from the Reference.

One possible solution
from turtle import *

speed(0)
hours = [2, 3, 1, 4, 6, 5, 2]


def colour_for(value):
    if value >= 5:
        return "tomato"
    elif value >= 3:
        return "gold"
    return "mediumseagreen"


def bar(height, colour):
    fillcolor(colour)
    pendown()
    begin_fill()
    left(90)
    forward(height)
    right(90)
    forward(30)
    right(90)
    forward(height)
    left(90)
    end_fill()
    penup()
    forward(10)


penup()
goto(-180, -100)
for h in hours:
    bar(h * 30, colour_for(h))
hideturtle()
Click-and-key art (after turtle-events; passing a function to an event (onscreenclick(fn)), global, a place in a list (a[0]), if)

Make a drawing toy: a click draws a shape where the mouse is (a dot, a square, anything), and keys change the colour, the shape or the size. Someone else should be able to play with it without reading your code.

Milestones:

  • A click draws a shape where I clicked.
  • At least two keys change what the next stamp looks like.
  • A friend used it without me explaining the keys (or the screen tells them).

Remind students to click the drawing first so keys reach it. The global line is the usual stumbling block; the friendly error names it.

One possible solution
from turtle import *

speed(0)
penup()
hideturtle()
colours = ["tomato", "gold", "teal", "purple"]
c = 0
size = 30
squares = False


def square(length):
    pendown()
    fillcolor(colours[c])
    begin_fill()
    for side in range(4):
        forward(length)
        left(90)
    end_fill()
    penup()


def draw_here(x, y):
    goto(x, y)
    if squares:
        square(size)
    else:
        dot(size, colours[c])


def next_colour():
    global c
    c = (c + 1) % len(colours)


def bigger():
    global size
    size = size + 10


def switch_shape():
    global squares
    squares = not squares


for x in range(-150, 151, 75):
    draw_here(x, 0)
    next_colour()
onscreenclick(draw_here)
onkey(next_colour, "c")
onkey(bigger, "b")
onkey(switch_shape, "s")
listen()
mainloop()
Your own game (after turtle-catch; passing a function to an event (onscreenclick(fn)), the random module, True / False as values, and / or)

Make a small game that is not Catch the turtle: a target that moves on a timer, something to click or dodge, a score and a way to win or lose. Keep it small enough to finish this week.

Milestones:

  • It runs, and something moves by itself on a timer.
  • The player scores by doing something, and the score shows on screen.
  • There is a way to win or lose, checked with and or or.
  • Someone else played it and I changed one thing because of what they did.

Scope is the risk: ask for a one-sentence pitch before students code. The last milestone is the play test from the Power-ups lesson; it is worth a short lesson of its own.

One possible solution
from turtle import *
import random

speed(0)
penup()
shape("circle")
color("tomato")
score = 0
lives = 5
caught = True
playing = True


def show():
    clear()
    here = position()
    goto(-190, 160)
    write("Score " + str(score) + "   Lives " + str(lives), False, "left", ("Arial", 16, "normal"))
    goto(here)


def move():
    global lives, caught, playing
    if not caught:
        lives = lives - 1
    if lives == 0 or score >= 10:
        playing = False
        show()
        hideturtle()
        return
    caught = False
    goto(random.randint(-150, 150), random.randint(-120, 120))
    show()
    ontimer(move, 1200)


def clicked(x, y):
    global score, caught
    if playing and not caught and abs(x - xcor()) < 20 and abs(y - ycor()) < 20:
        score = score + 1
        caught = True
        show()


onscreenclick(clicked)
move()
mainloop()