A robot with a pen#
Picture a small robot sitting on a big sheet of paper, holding a pen against it. You can only give it simple orders: walk forward 100 steps, turn left 90 degrees, lift the pen, put the pen down. Wherever it walks with the pen down, it leaves a line.
That robot is Python’s turtle, from the turtle module that comes with most Python installs. (On some Linux systems the graphics package it needs, tkinter, is installed separately.) Courses use it early for two reasons. A loop that repeats is suddenly something you can watch, and a mistake in it is a wrong picture you can see at a glance. And the turtle is an object: a thing in your program that has its own data (where it is, which way it faces, whether its pen is down) and its own actions, called methods, that you call with a dot, like t.forward(100).
Setting up: the screen and the turtle#
Every turtle program has the same frame:
import turtle # load the module
screen = turtle.Screen() # the window and the paper
t = turtle.Turtle() # one turtle object, named t
# ... drawing commands go here ...
turtle.done() # keep the window open until you close it
The paper is a grid. The turtle starts in the centre, at coordinates (0, 0), facing right (east). The x value grows to the right and y grows upwards, as in maths class. Turning left is anticlockwise; right is clockwise. Without turtle.done() at the end, the window can close the moment the program finishes, before you see anything; inside some editors, such as IDLE, it stays open anyway, which is why the bug comes and goes.
Moving, turning and lifting the pen#
| Method | Does |
|---|---|
t.forward(d), t.backward(d) | walks d steps in the direction it faces, or the opposite way |
t.left(a), t.right(a) | turns on the spot by a degrees; draws nothing |
t.penup(), t.pendown() | lifts the pen so moves leave no line, or puts it back down |
t.goto(x, y) | moves straight to that point (drawing if the pen is down) |
t.setheading(a) | faces an exact direction: 0 east, 90 north, 180 west, 270 south |
t.circle(r) | draws a circle of radius r, curving to the turtle’s left |
import turtle
t = turtle.Turtle()
for i in range(3):
t.forward(40)
t.left(90)
t.forward(40)
t.right(90)
t.penup()
t.goto(0, -60)
t.pendown()
t.forward(120)
turtle.done()
Three steps drawn, then the pen lifted, a jump to a new spot, and the pen put down to draw a final line. The gap in the picture is the penup. Note that left and right only turn: if you forget a forward, nothing appears for that step.
Loops and the 360 rule#
A square is “forward, turn left 90”, four times. That repetition is a for loop:
import turtle
t = turtle.Turtle()
for side in range(4):
t.forward(100)
t.left(90)
turtle.done()
Why 90? Walk all the way round any closed shape and you end up facing the way you started: a full turn of 360 degrees, shared equally between the corners. So the rule for a regular shape with n sides is: turn 360 / n at every corner. Square: 360 / 4 = 90. Triangle: 360 / 3 = 120. Hexagon: 360 / 6 = 60.
The classic mistake is to turn by the angle inside the corner. A triangle’s inside angles are 60 degrees, so it is tempting to write left(60):
import turtle
t = turtle.Turtle()
for side in range(3):
t.forward(100)
t.left(60)
turtle.done()
Turning 60 three times is only 180 degrees in total, so the turtle has turned half way round and the shape never closes. With 120, the turn the turtle actually makes (the outside angle), it does:
import turtle
def polygon(t, n, size):
for side in range(n):
t.forward(size)
t.left(360 / n)
t = turtle.Turtle()
x = -260
for n in [3, 4, 5, 6]:
t.penup()
t.goto(x, 0)
t.pendown()
polygon(t, n, 70)
x = x + 140
turtle.done()
One function with a loop inside draws every one of those shapes. The sides and the turn both come from n, so changing one number changes the shape.
Colour, thickness and fill#
| Method | Does |
|---|---|
t.color("blue") | sets the pen (and fill) colour by name, or t.color("navy", "gold") for pen and fill separately |
t.pensize(w) | line thickness |
t.begin_fill() … t.end_fill() | fills the shape drawn between the two calls |
t.speed(0) | fastest drawing; 1 is slowest, 10 fast |
t.hideturtle(), t.shape("turtle") | hides the arrow, or changes it into a turtle |
screen.bgcolor("lightblue") | colours the background (a screen method, not a turtle one) |
import turtle
t = turtle.Turtle()
t.pensize(4)
t.color("navy", "gold")
t.begin_fill()
for side in range(4):
t.forward(100)
t.left(90)
t.end_fill()
t.penup()
t.goto(200, 0)
t.pendown()
t.color("darkred", "salmon")
t.begin_fill()
t.circle(50)
t.end_fill()
turtle.done()
The fill needs both calls. Call begin_fill, draw a closed outline, then end_fill, and the inside is painted. Forget end_fill and no fill appears at all.
Functions, and loops inside loops#
Once a shape is in a function, a second loop can repeat the whole shape. Draw a square, turn a little, draw another square, and so on: the outer loop runs 12 times and the inner loop (inside square) runs 4 times for each, so the turtle draws 48 sides in all.
import turtle
def square(t, size):
for side in range(4):
t.forward(size)
t.left(90)
t = turtle.Turtle()
t.speed(0)
for i in range(12):
square(t, 80)
t.left(30)
turtle.done()
The function takes the turtle as a parameter (t), so the same function can draw with any turtle you hand it. The outer turn is 360 / 12 = 30: the same 360 rule, applied to the whole pattern.
Several turtles: objects and their own state#
Each call to turtle.Turtle() makes a brand-new turtle object with its own position, heading, colour and pen. These are called instances: separate objects made from the same blueprint. Moving one never moves another:
import turtle
ana = turtle.Turtle()
ben = turtle.Turtle()
ana.color("teal")
ben.color("purple")
ana.pensize(3)
ben.pensize(3)
ben.left(90)
for i in range(4):
ana.forward(60)
ana.left(45)
ben.forward(60)
ben.right(45)
turtle.done()
ana and ben share nothing but the paper. Each method call goes to the object named before the dot. That is the habit the turtle is quietly teaching: ana.forward(100) means “ana, walk forward”, exactly as name.upper() later means “this string, give me an uppercase copy”.
A turtle can also tell you its state: t.position() returns its coordinates and t.heading() its direction. After the square earlier, printing t.position() shows (-0.00,0.00) and t.heading() shows 0.0: a closed shape brings the turtle back to where it started, facing the same way. (We checked by running it. The minus sign is a tiny rounding leftover from the turning maths, a number like -0.00000000000001 printed to two decimal places.)
Each corner of a regular shape with n sides turns 360 / n degrees, so a loop of “forward, turn” repeated n times draws it. Every turtle is its own object: the name before the dot decides which one moves.
Where these go wrong#
- Turning by the inside angle. A triangle needs
left(120), notleft(60). Turn360 / n. - Naming your own file
turtle.py.import turtlethen imports your file instead of Python’s module, and the program fails withAttributeError: partially initialized module 'turtle' has no attribute 'Turtle' (most likely due to a circular import). (Python 3.13 and later word it differently and suggest renaming the file.) Rename the file, and delete anyturtle.pycopy left in the folder. - Forgetting
turtle.done(). The window may vanish as soon as the drawing finishes. - Writing
t.Forward(100)orturtle.turtle(). Method names are lowercase; the class isTurtlewith a capital T. Both mistakes raiseAttributeError. - Drawing while moving to a new start point. Put
penup()beforegotoandpendown()after. - Calling
begin_fillwithoutend_fill. The shape is never filled. - Expecting y to grow downwards. In turtle graphics, positive y is up and (0, 0) is the centre of the window.
Practice#
Answer each one on paper before you look at the solutions. Every answer that involves running code was checked by running it.
- A turtle starts at (0, 0) facing east. It runs
forward(50),left(90),forward(30). Where is it, and which way does it face? - How many degrees should the turtle turn at each corner of a regular pentagon, a regular octagon and a regular 10-sided shape?
- Using the
polygon(t, n, size)function from this guide, write the code to draw an octagon with sides of 50. - This code is meant to draw a triangle but does not. Explain what it draws and fix it.
for side in range(3): t.forward(100) t.left(60) - A five-pointed star is drawn with five lines, turning right 144 degrees after each. Explain why 144 works, then write the loop.
- You make two turtles,
a = turtle.Turtle()andb = turtle.Turtle(), then calla.left(90). Which way doesbface? What does this show?
Solutions#
- At (50, 30), facing north (heading 90). The first move goes 50 to the right; the left turn makes it face up; the second move goes 30 up.
- 360 / 5 = 72, 360 / 8 = 45 and 360 / 10 = 36.
- Pass 8 for
n; the function works out the 45-degree turn itself:import turtle def polygon(t, n, size): for side in range(n): t.forward(size) t.left(360 / n) t = turtle.Turtle() polygon(t, 8, 50) turtle.done()An octagon: eight sides, turning 45 degrees. Drawn by running the program above. - It turns only 3 × 60 = 180 degrees in total, so the shape never closes: it draws three sides of a hexagon. Change the turn to
t.left(120), which is 360 / 3. - A star’s path goes round the centre twice before it closes, so its five turns add up to 720 degrees, and 720 / 5 = 144.
import turtle t = turtle.Turtle() for point in range(5): t.forward(150) t.right(144) turtle.done()A five-pointed star: five lines, turning 144 degrees each time. Drawn by running the program above. bstill faces east (heading 0). Each turtle is a separate object with its own state; a method call changes only the object named before the dot.
Test-readiness checklist#
These are the skills a first programming course tests on this topic. Tick each one only when you can do it without looking.
- ☐ I can set up a turtle program: import, Screen, Turtle, and
turtle.done(). - ☐ I can predict a turtle’s position and heading after a few moves, using the centre-origin, y-up grid.
- ☐ I can draw any regular polygon with a loop, turning 360 / n each time.
- ☐ I can lift and lower the pen, move with goto, and set colour, pen size and fill.
- ☐ I can write a drawing function that takes the turtle as a parameter, and nest loops to repeat a shape.
- ☐ I can explain what an object, a method and an instance are, using two turtles as the example.
Test yourself in the free Kestrel Exams app
12 practice questions on turtle positions, headings, turns and shapes, every answer checked by running the program. Free, offline, no account.
Practise turtle graphics →Frequently asked questions#
How do you draw a square with Python turtle?
Repeat forward and left four times: for side in range(4): t.forward(100) then t.left(90). Each corner turns 90 degrees, which is 360 divided by 4.
How do you calculate the turning angle for a polygon in turtle?
Divide 360 by the number of sides. A triangle turns 120 degrees at each corner, a square 90, a pentagon 72 and a hexagon 60. That is the outside angle; turning by the inside angle is the most common mistake.
Why does my turtle window close immediately?
The program finished and the window closed with it. Add turtle.done() as the last line so the window stays open until you close it, or screen.exitonclick() so it stays open until you click inside it.
Why do I get "partially initialized module turtle has no attribute Turtle"?
Your own file is named turtle.py, so import turtle imports your file instead of Python's turtle module. Python 3.13 and later show a different message that suggests renaming the file. Either way, rename the file and delete any leftover turtle.py in the same folder.
What do penup and pendown do?
penup lifts the pen so the turtle moves without drawing, and pendown puts it back so movement draws a line. Use penup before goto to jump to a new starting point without leaving a line.
How do you fill a shape with colour in turtle?
Set the fill colour with t.color(pen_colour, fill_colour) or t.fillcolor(...), call t.begin_fill(), draw the closed shape, then call t.end_fill(). The inside is filled when end_fill runs.
Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.