← Objects with turtles

One dictionary per star

Keep everything about one star together in a dictionary, so adding a property is one line and nothing can fall out of step.

A contact on your phone keeps a name, a number and a photo together. A dictionary does the same for anything in a program.

Four lists for one star was fragile. A dictionary keeps everything about one star together: each value is stored under a name, called a key. The game keeps a list of dictionaries, one per star.

PredictRead the code and say what it will do before you run anything. A wrong guess is fine: it shows you what to look for.

Predict

stars.py
star = {"speed": 5, "points": 2}
star["points"] = star["points"] + 1
print(star["speed"], star["points"])

{"speed": 5, "points": 2} is a dictionary: the key "speed" is paired with 5 and "points" with 2. star["points"] is the value stored under "points". What will it print?

What does it print?

RunRun it and compare the result with your prediction.

Run

The same game again. Each star is now one dictionary holding its turtle, speed and points, and for star in stars: visits each dictionary in turn. Play it, then find star["speed"] in tick.

stars.py
from turtle import *
import random

speed(0)
penup()
goto(0, -180)
left(90)
score = 0

pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)

stars = []
for i in range(4):
    s = Turtle()
    s.shape("circle")
    s.penup()
    s.goto(-150 + i * 100, 200)
    s.setheading(270)
    stars.append({
        "turtle": s,
        "speed": random.randint(3, 7),
        "points": 1,
    })

for star in stars:
    star["turtle"].color("gold")

def show_score():
    pen.clear()
    pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))

def go_left():
    goto(xcor() - 25, ycor())

def go_right():
    goto(xcor() + 25, ycor())

def tick():
    global score
    for star in stars:
        star["turtle"].forward(star["speed"])
        if star["turtle"].distance(xcor(), ycor()) < 25:
            score += star["points"]
            star["turtle"].goto(random.randint(-200, 200), 200)
        if star["turtle"].ycor() < -220:
            star["turtle"].goto(random.randint(-200, 200), 200)
    show_score()
    ontimer(tick, 50)

onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
Try it yourselfYour edits are saved in this browser.

InvestigateTrace how each line of code connects to what you see.

Investigate

stars.py
from turtle import *
import random

speed(0)
penup()
goto(0, -180)
left(90)
score = 0

pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)

stars = []
for i in range(4):
    s = Turtle()
    s.shape("circle")
    s.penup()
    s.goto(-150 + i * 100, 200)
    s.setheading(270)
    stars.append({
        "turtle": s,
        "speed": random.randint(3, 7),
        "points": 1,
    })

for star in stars:
    star["turtle"].color("gold")

def show_score():
    pen.clear()
    pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))

def go_left():
    goto(xcor() - 25, ycor())

def go_right():
    goto(xcor() + 25, ycor())

def tick():
    global score
    for star in stars:
        star["turtle"].forward(star["speed"])
        if star["turtle"].distance(xcor(), ycor()) < 25:
            score += star["points"]
            star["turtle"].goto(random.randint(-200, 200), 200)
        if star["turtle"].ycor() < -220:
            star["turtle"].goto(random.randint(-200, 200), 200)
    show_score()
    ontimer(tick, 50)

onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()

What each part of a dictionary does.

How much changes when every star needs one more value?

A key without its quotes.

Match each piece with what it does.

{"speed": 5, "points": 1}
star["speed"]
star["points"] = 3
for star in stars:

Every star should also remember its colour. What changes?

This should print each star's speed doubled, but it stops with a NameError. Click the line that causes it.

ModifyChange the code on purpose and check the result.

Modify

Give each star a random 1 to 3 points.

Need a hint?

"points": 1 gives every star 1 point. Use random.randint(1, 3) instead.

Store a colour in each star's dictionary, and use it to colour the turtle.

Need a hint?

Add a list of colours before the loop, and a "colour" key in each dictionary: colours[i % 3] picks gold, orange, yellow in turn.

Another hint

Then colour each turtle with star["turtle"].color(star["colour"]).

Try it yourselfYour edits are saved in this browser.

Give each star a random 1 to 3 points.

    Run your program. This ticks when your code does all of the above.

    Store a colour in each star and use it to colour the turtle.

      Run your program. This ticks when your code does all of the above.

      MakeBuild something new using what you have learned. Expect a few tries; that is normal.

      Make a bad star

      Make the first star a bad star again, this time with a "bad" key in each dictionary (True for the first star only). The bad star is red and costs 3 points when caught. Compare it with last lesson's version: what did you not have to do this time?

      Try it yourselfYour edits are saved in this browser.

      Add a "bad" key: the first star is red and costs 3 points when caught.

        Run your program. This ticks when your code does all of the above.

        Info

        Where this leads

        A list of dictionaries is how most programs store data: one record per thing. There is still one awkward part: star["turtle"].forward(star["speed"]). Next lesson makes a Star of your own, so it reads star.turtle.forward(star.speed).

        A school stores each student as a dictionary: {"name": "Ada", "year": 9}. What is a list of them?

        For teachers

        Students keep each star's turtle, speed and points together in a dictionary, loop over a list of dictionaries, and see that a new property is now one key instead of one more list kept in step. About 50 minutes.

        Open the teacher guide: answers, solutions, slides and a worksheet.

        Students will be able to

        Before class

        Read the unit primer first. A dictionary pairs keys with values: {"speed": 5, "points": 2}. star["speed"] reads the value; star["speed"] = 8 changes it. Keys are text, so they need quotes; star[speed] (the bug task) looks for a variable called speed and stops with a NameError. A list of dictionaries is a table: one row per thing. The Make task repeats last lesson's bad star so students can compare a new list with a new key.

        Running the lesson

        1. Predict: read the second line from the right: work out star["points"] + 1, then store it under "points".
        2. Run: ask students to find where a star's speed is stored and where it is read.
        3. Investigate: the colour question is the lesson's point. One key, made in one place.
        4. Bug task: quotes make it text. Without them Python looks for a variable.
        5. Make: compare with last lesson's bad star. No list to keep in step.

        The hard part (on purpose)

        Keys are text in quotes: star["speed"], not star[speed]. Ask them to read the NameError aloud and say what Python thinks speed is.

        When students get stuck

        Stretch and support

        Stretch: Add a "hits" key that counts how often each star has been caught, and make a star faster every third catch.

        Support: Give students the "bad" key already in the dictionary and ask them only to change what happens when a star is caught.

        Where it leads

        Next lesson makes a Star class, so a star's values read star.speed instead of star["speed"], and later the star can do things itself. Data detective uses lists of dictionaries for real data sets.

        What each step is for

        Now you can
        Next lesson4. A Star classMake a new kind of object with class, set up each one in __init__, and store its values with self.