24  Turtle: the object

This week you met objects and their methods. You learned that a string is a thing that knows how to do something to itself, that 'atgc'.upper() is the way you ask it, and that the same idea explains lists, dictionaries and tuples. Everything in this session is that same idea seen from a second angle, because a turtle is an object too, and the ways it differs from a string are exactly the ways beginners get objects wrong.

A turtle is a little machine that lives on a canvas, holds a position and a direction, carries a pen that is either down or up, and obeys methods you call on it. When you tell it to move forward it leaves a line behind, and after it has moved it is somewhere else. That is the whole of it, and it is enough to make one distinction very concrete. A string method hands you a new string and leaves the original string exactly as it was. A turtle method changes the turtle and hands the turtle back. Both are methods, both are called with a dot, and they behave in opposite ways, which is why having both in front of you at once is worth an hour.

The turtle also gives you somewhere to put the containers you met in the same week. A drawing is a natural thing to describe with a list of distances, a dictionary from a letter to a colour, or a tuple of two coordinates, and you will do all three before the end of this session. The turtle’s own answer to the question of where it is comes back as a tuple, so you will meet tuple unpacking on real output rather than on an invented example.

Getting a turtle on the screen

Turtle exercises are ordinary notebook cells and not %%sandbox scripts, because the drawing appears underneath the cell that made it. The rule that follows from this is simple and you should adopt it now: everything belonging to one drawing goes in one cell, including the line that creates the turtle. If you create a turtle in one cell and try to drive it from the next, you will get no picture, because the picture was already drawn and finished at the end of the first cell.

If you are working in the browser version of the notebooks, install the widget once with the following line. If you are working in your own environment where it is already installed, skip it.

%pip install -q turtle-widget

Then, in every cell that draws something, start by importing and making a turtle.

from turtle_widget import Turtle

t = Turtle()
t.forward(100)

Run that. The turtle starts in the middle of the canvas facing right, and the line it leaves behind is the evidence that it moved. Notice that you did not have to write anything on the last line of the cell to make the drawing appear. The turtle shows itself when the cell ends.

Exercise 24-1

SOLO

Decide, before you run it, where the turtle will end up and which way it will be facing. Then run it and see whether the picture agrees with you.

from turtle_widget import Turtle

t = Turtle()
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)

The method left turns the turtle counter-clockwise by the number of degrees you give it, and there is a matching right. Neither of them moves the turtle. A turn changes only which way the turtle is facing, and it needs saying out loud because a great many wrong drawings come from forgetting it.

Exercise 24-2

SOLO

Here is a string doing what strings do. Decide what each of the two print calls will show before you run the cell.

dna = 'atgctagc'
dna.upper()
print(dna)
print(dna.upper())

You have seen this before, and the lesson is that dna.upper() produces a new string and leaves dna alone, so calling it on a line by itself accomplishes nothing at all. The result was made and immediately thrown away.

Now do the same thing to a turtle and watch it behave in the opposite way.

from turtle_widget import Turtle

t = Turtle()
t.forward(100)
print(t.position())

Calling t.forward(100) on a line by itself is not a wasted line. It is the whole point. The turtle did not hand you a new turtle that had moved. It moved.

Commands and questions

Turtle methods come in two kinds, and telling them apart is the skill this section builds. A command tells the turtle to do something, and its effect is a change in the turtle. Methods like forward, backward, left, right, penup, pendown and goto are commands. A question asks the turtle about itself and hands you back an answer, and the turtle is unchanged by being asked. Methods like position, xcor, ycor, heading, isdown and isvisible are questions.

The string methods you met this week are all questions in this sense, even the ones that sound like commands. When you ask a string to capitalise itself, it does not change. It works out what a capitalised version would look like and hands you that instead. A string cannot be changed at all, which is what immutable means, and it is the reason every useful string method returns something you have to catch. The turtle is the other case. It can be changed, and its commands change it.

Exercise 24-3

SOLO

What does a turtle command hand back? Run this and look at what the second and third lines draw.

from turtle_widget import Turtle

t = Turtle()
t.forward(80).left(120).forward(80)
t.left(120).forward(80)

That works because each command hands the turtle itself back, already changed, so the next dot in the line has a turtle to talk to. It is the same turtle every time, and not a copy. Chaining like this is legal, and you should recognise it when you see it, but for anything longer than a couple of steps a separate line for each command is far easier to read and far easier to trace in your head.

Exercise 24-4

AI: Explainer

Ask the assistant to explain, in three sentences and without code, why dna.upper() on a line by itself does nothing useful while t.forward(100) on a line by itself does everything you wanted. Then decide whether its explanation is right, and confirm the part of it you are least sure about by writing a few lines and running them. An explanation stays provisional until the machine has agreed with it, and this week the machine is a turtle.

Asking the turtle where it is

The questions are the part of the turtle that will matter most later in the course, so get used to them now. The turtle’s canvas has its origin in the middle, x growing to the right and y growing upwards. A heading of zero means facing right, and the heading grows as the turtle turns counter-clockwise, so ninety is straight up.

Exercise 24-5

SOLO

Write down the three numbers you expect before you run this. Then run it.

from turtle_widget import Turtle

t = Turtle()
t.forward(100)
t.left(90)
t.forward(50)
print(t.xcor())
print(t.ycor())
print(t.heading())

If any of the three surprised you, do the substitution in your head one line at a time until you can say where the turtle was after each command. The picture and the numbers are two reports of the same fact, and if they disagree in your head then one of them is wrong and it is worth finding out which.

Now ask the same question a second way. The method position answers with both coordinates at once, packed into a tuple. Predict the two lines of output before running.

from turtle_widget import Turtle

t = Turtle()
t.forward(120)
t.left(90)
t.forward(60)
here = t.position()
print(here)
x, y = t.position()
print(y)

The last two lines are tuple unpacking, exactly as you met it this week. The tuple has two items, the two names on the left take one each, and the order is the order in the tuple.

Exercise 24-6

SOLO

This one is meant to fail, and the error is the point. Predict which line raises the error and roughly what it will say, then run it and read the message carefully.

from turtle_widget import Turtle

t = Turtle()
t.forward(100)
here = t.position()
here[0] = 0
print(here)

A tuple cannot be changed after it is made, so there is no way to assign into one. Notice what this means for the turtle. The tuple you got back is a report of where the turtle was when you asked, and rewriting the report would not move the turtle even if Python let you. To move the turtle you have to give the turtle a command.

Exercise 24-7

SOLO

The pen is a piece of the turtle’s state just like its position, and there is a question for it. Predict all three printed values before running.

from turtle_widget import Turtle

t = Turtle()
print(t.isdown())
t.forward(80)
t.penup()
print(t.isdown())
t.forward(80)
t.pendown()
t.forward(80)
print(t.isdown())

Look at the picture as well as the numbers. The turtle travelled the same distance three times and the canvas shows only two lines. The middle journey happened, and left no trace of itself, which is a small preview of something that becomes important in week eight.

Two names, one turtle

This week you saw that giving a list a second name does not give you a second list. Turtles behave the same way, and because a turtle is visible the demonstration is unusually blunt.

Exercise 24-8

SOLO

Decide what the picture will look like and what the final line will print, then run it.

from turtle_widget import Turtle

t = Turtle()
other = t
other.forward(100)
other.left(90)
other.forward(100)
print(t.position())

There is one turtle on that canvas and it has two names. Everything you did through other happened to t, because other and t were never two things. This is the same fact you met with a = [1, 2, 3] followed by b = a, and it is worth having met it twice, in two places where the consequences look completely different.

Lists and dictionaries that describe a drawing

A drawing is data before it is a picture, and this section is where you start writing the data down. You do not yet have loops, so you will index into your containers by hand, which is a perfectly good way to see what is in them.

Exercise 24-9

SOLO

Fill in the three missing lines so that the turtle walks all four distances in the list, turning ninety degrees to the left after each one. Take each distance out of the list by its index rather than typing the number again.

from turtle_widget import Turtle

distances = [120, 60, 120, 60]

t = Turtle()
t.forward(distances[0])
t.left(90)

When it works, change one number in the list, run the cell again, and watch the drawing follow the data. Nothing in the drawing commands mentions a size any more. The sizes all live in one place, and that is the beginning of a habit that will carry you a long way.

Exercise 24-10

SOLO

A dictionary is the natural way to say that each base gets its own colour. Predict which three colours appear, in which order, then run it.

from turtle_widget import Turtle

colour = {'A': 'green', 'T': 'red', 'G': 'black', 'C': 'blue'}
dna = 'GAT'

t = Turtle()
t.pensize(6)
t.pencolor(colour[dna[0]])
t.forward(80)
t.pencolor(colour[dna[1]])
t.forward(80)
t.pencolor(colour[dna[2]])
t.forward(80)

Read the expression colour[dna[0]] from the inside out, exactly as you would reduce any other expression. First dna[0] reduces to 'G', then colour['G'] reduces to 'black', and only then does the method get called. Two lookups of two different kinds sit in that one pair of brackets, one into a string by position and one into a dictionary by key, and being able to take them apart calmly is most of what indexing is.

Next week the turtle gets loops, and everything you just typed out three times will collapse into three lines that work for a strand of any length.