There are many modules in Python that provide very powerful features that we can use in our own programs. Some of these can send email, or fetch web pages. The one we’ll look at in this chapter allows us to create turtles and get them to draw shapes and patterns.
The turtles are fun, but the real purpose of the chapter is to teach ourselves a little more Python, and to develop our theme of computational thinking, or thinking like a computer scientist. Most of the Python covered here will be explored in more depth later.
Let’s try a couple of lines in the Python shell to create a new turtle and start drawing a rectangle. (We’ll call the variable that refers to our first turtle alex, but you can choose another name if you follow the naming rules from the previous chapter).
1 2 3 4 5 6 7 | >>> import turtle
>>> turtle.setup(800, 600)
>>> alex = turtle.Turtle()
>>> alex.forward(300)
>>> alex.left(90)
>>> alex.forward(200)
>>> exit()
|
After the second command, a new window pops up. The third command places a cursor – affectionately called a turtle in this module – which we have named alex.
The next three lines move alex forward, turn him left, and move him forward again, completing two sides of a rectangle. After these commands have been entered, you will see a window that looks like this:
Here are a couple of things you’ll need to understand about this program.
Go ahead and click on the window after entering the last command.
An object can have various methods — things it can do — and it can also have attributes — (sometimes called properties). For example, each turtle has a color attribute. The method invocation alex.color("red") will make alex red, and drawing will be red too.
The color of the turtle, the width of its pen, the position of the turtle within the window, which way it is facing, and so on are all part of its current state. Similarly, the window object has a background color, and some text in the title bar, and a size and position on the screen. These are all part of the state of the window object.
Quite a number of methods exist that allow us to modify the turtle and the window objects. We’ll just show a couple. We’ve only commented those lines that are different from the previous example (and we’ve used a different variable name for this turtle). Also, we’ll put this example in a script named tess.py, since it is getting a bit too long to type over and over into the Python shell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import turtle
turtle.setup(800, 600) # set the window size to 800 by 600 pixels
wn = turtle.Screen() # set wn to the window object
wn.bgcolor("lightgreen") # set the window background color
wn.title("Hello, Tess!") # set the window title
tess = turtle.Turtle()
tess.color("blue") # make tess blue
tess.pensize(3) # set the width of her pen
tess.forward(300)
tess.left(120)
tess.forward(300)
wn.exitonclick()
|
Running this program will create a graphics window that looks like this:
When we run this program, this new window pops up, and will remain on the screen until we click on it.
Extend this program ...
Just like we can have many different integers in a program, we can have many turtles. Each of them is called an instance. Each instance has its own attributes and methods — so alex might draw with a thin black pen and be at some position, while tess might be going in her own direction with a fat pink pen. So here is what happens when alex completes his rectangle, and tess completes her triangle, in a program named tess_n_alex.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import turtle
# setup the window and its attributes
turtle.setup(800, 600)
wn = turtle.Screen()
wn.bgcolor("lightgreen")
wn.title("Tess & Alex")
# instantiate (create) tess and set her attributes
tess = turtle.Turtle()
tess.color("hotpink")
tess.pensize(5)
# instantiate alex
alex = turtle.Turtle()
# draw an equilateral triangle with tess
tess.forward(320)
tess.left(120)
tess.forward(320)
tess.left(120)
tess.forward(320)
tess.left(120)
# turn tess around and move her away from the origin
tess.right(180)
tess.forward(320)
# make alex draw a square
alex.forward(200)
alex.left(90)
alex.forward(200)
alex.left(90)
alex.forward(200)
alex.left(90)
alex.forward(200)
wn.exitonclick()
|
which generates this when run:
Here are some How to think like a computer scientist observations:
When we drew the square, it was quite tedious. We had to move then turn, move then turn, etc. etc., four times. If we were drawing a hexagon, or an octogon, or a polygon with 42 sides, it would have been a nightmare.
So a basic building block of all programs is to be able to repeat some code, over and over again.
Python’s for loop solves this for us.
Let’s say we have some friends, and we’d like to send them each an email inviting them to our party. Since we don’t know how to send email yet, for the moment we’ll just print a message for each friend:
1 2 3 | for f in ["Joe", "Amy", "Brad", "Angelina", "Zuki", "Thandi", "Paris"]:
invitation = "Hi " + f + ". Please come to my party on Saturday!"
print(invitation)
|
When we run this, the output looks like this:
Hi Joe. Please come to my party on Saturday!
Hi Amy. Please come to my party on Saturday!
Hi Brad. Please come to my party on Saturday!
Hi Angelina. Please come to my party on Saturday!
Hi Zuki. Please come to my party on Saturday!
Hi Thandi. Please come to my party on Saturday!
Hi Paris. Please come to my party on Saturday!
Study this example closely and note the following things:
As a program executes, the interpreter always keeps track of which statement is about to be executed. We call this the control flow, of the flow of execution of the program. When humans execute programs, they often use their finger to point to each statement in turn. So you could think of control flow as “Python’s moving finger”.
Control flow until now has been strictly top to bottom, one statement at a time. The for loop changes this.
Control flow is often easy to visualize and understand if we draw a flowchart. This shows the exact steps and logic of how the for statement executes.
To draw a square we’d like to do the same thing four times — move the turtle, and turn. We previously used 8 lines to have alex draw the four sides of a square. This does exactly the same, but using just three lines:
for i in [0, 1, 2, 3]:
alex.forward(250)
alex.left(90)
While saving some lines of code might be convenient, it is not the big deal here. What is much more important is that we’ve found a repeating pattern of statements, and reorganized our program to repeat the pattern. Finding the chunks and somehow getting our programs arranged around those chunks is a vital skill in How to think like a computer scientist.
The values in the list, [0, 1, 2, 3], were provided to make the loop body execute 4 times. We could have used any four values, but these are the conventional ones to use. In fact, they are so popular that Python gives us a special built-in range function for this purpose.
>>> for i in range(4):
... print(i)
...
0
1
2
3
>>>
Note that:
We can also create a list of numbers by passing the output of a call to the range function to the the list type function:
>>> list(range(6))
[0, 1, 2, 3, 4, 5]
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Try this...
What does list(range(0)) return? What about list(range(1))?
Our little trick earlier to make sure that alex did the final turn to complete 360 degrees has paid off: if we had not done that, then we would not have been able to use a loop for the fourth side of the square. It would have become a “special case”, different from the other sides. When possible, we’d much prefer to make our code fit a general pattern, rather than have to create a special case.
So to repeat something four times, a good Python programmer would do this:
for i in range(4):
alex.forward(250)
alex.left(90)
By now you should be able to see how to change our previous program so that tess can also use a for loop to draw her equilateral triangle.
What would happen if we made this change ...
for clr in ["yellow", "red", "purple", "blue"]:
alex.color(clr)
alex.forward(250)
alex.left(90)
A variable can also be assigned a value that is a list. So lists can also be used in situations other than the for loop. The code above could be rewritten like this:
colors = ["yellow", "red", "purple", "blue"]
for clr in colors:
alex.color(clr)
alex.forward(250)
alex.left(90)
Turtle methods can use negative angles or distances. So tess.foward(-100) will move tess backwards, and tess.left(-30) turns her to the right. Additionally, because there are 360 degrees in a circle, turning 30 to the left will get you facing in the same direction as turning 330 to the right! (The on-screen animation will differ, though — you will be able to tell if tess is turning clockwise or counter-clockwise!)
This suggests that we don’t need both a left and a right turn method — we could be minimalists, and just have one method. There is also a backward method. (If you are very nerdy, you might enjoy saying alex.backward(-100) to move alex forward!)
Part of thinking like a scientist is to understand more of the structure and rich relationships in your field. So revising a few basic facts about geometry and number lines, like we’re done here is a good start if we’re going to play with turtles.
A turtle’s pen can be picked up or put down. This allows us to move a turtle to a different place without drawing a line. The methods are
alex.penup()
alex.forward(100) # this moves alex, but no line is drawn
alex.pendown()
Every turtle can have its own shape. The ones available “out of the box” are arrow, blank, circle, classic, square, triangle, turtle.
alex.shape("turtle")
You can speed up or slow down the turtle’s animation speed. (Animation controls how quickly the turtle turns and moves forward). Speed settings can be set between 1 (slowest) to 10 (fastest). But if you set the speed to 0, it has a special meaning — turn off animation and go as fast as possible.
alex.speed(10)
A turtle can “stamp” its footprint onto the canvas, and this will remain after the turtle has moved somewhere else. Stamping works, even when the pen is up.
Let’s do an example that shows off some of these new features in spiral.py:
import turtle
turtle.setup(800, 600)
wn = turtle.Screen()
wn.bgcolor("lightgreen")
wn.title("Tess's Spiral")
tess = turtle.Turtle()
tess.shape("turtle")
tess.color("blue")
tess.penup() # this is new
size = 20
for i in range(30):
tess.stamp() # leave an impression on the canvas
size = size + 3 # increase the size on every iteration
tess.forward(size) # move tess along
tess.right(24) # and turn her
wn.exitonclick()
which generates this when run:
Be careful now: all except one of the shapes you see on the screen here are footprints created by stamp. But the program still only has one turtle instance — can you figure out which one is the real tess? (Hint: if you’re not sure, write a new line of code after the for loop to change tess’ color, or to put her pen down and draw a line, or to change her shape, etc.)
Write a program that prints We like Python's turtles! 100 times.
The vocabularly used with software objects was inspired by objects in the real world. Let’s reverse the thought process, and describe a real world object, your cellphone, using the same vocabularly we use with software objects.
Give three attributes of your cellphone. Give three methods of your cellphone.
Create a list named months that contains 12 strings with the names of the months of the year in the order in which they occur.
Assume you have the assignment xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
Extra challenges (for really smart students) ...
Use for loops to make a turtle draw these regular polygons (regular means all sides the same lengths, all angles the same):
A drunk student makes a random turn and then takes 100 steps forward, makes another random turn, takes another 100 steps, turns another random amount, etc. A social science student records the angle of each turn before the next 100 steps are taken. Her experimental data is [160, -43, 270, -97, -43, 200, -940, 17, -86]. (Positive angles are counter-clockwise.) Use a turtle to draw the path taken by our drunk friend.
Enhance your program above to also tell us what the drunk student’s heading is after he has finished stumbling around. (Assume he begins at heading 0).
If you were going to draw a regular polygon with 18 sides, what angle would you need to turn the turtle at each corner?
At the interactive prompt, anticipate what each of the following lines will do, and then record what happens. Score yourself, giving yourself one point for each one you anticipate correctly
>>> import turtle
>>> wn = turtle.Screen()
>>> tess = turtle.Turtle()
>>> tess.right(90)
>>> tess.left(3600)
>>> tess.right(-90)
>>> tess.speed(10)
>>> tess.left(3600)
>>> tess.speed(0)
>>> tess.left(3645)
>>> tess.forward(-100)
Write a program to draw a shape like this:
Hints
Write a program that will draw a screen that looks something like this:
Hint
Use a combination of the penup, forward, pendown, stamp, and backward turtle methods to get this to work.
The turtle should end up back where it started when your program finishes.
Now build on your solution from the previous exercise to Write a program to draw a face of a clock that looks something like this:
Create a turtle, and assign it to a variable. When you ask for its type, what do you get?
What is the collective noun for turtles? (Hint: they don’t come in herds.)