Class 2 : Programmers Are Lazy

We mentioned this in the last class, but if you’re going to be a programmer, you have to embrace basic laziness. Programmers don’t like to repeat themselves and always look for ways to write less code rather than more to get the same things done. In our last class we saw how using a for loop could reduce the amount of code we had to write to draw a flower. We used a loop to repeat drawing the “petals” of our flower so we didn’t have to write code for every one. Let’s learn about another tool we can put in our programmers toolbelt called functions.

Functions

Functions allow us to use the same set Python statements over and over again, and even change what the Python code does without having to change the code. We’ve already used functions in the previous session in our turtle program. We used the range() function as part of a for loop. The range() function is built into Python, but what does it do? It creates a list of numbers, as simple as that. Let’s start Idle, get into interactive mode and enter this at the Python command prompt:

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

The range(10) function generated a list of numbers from 0 to 9 (10 total). Notice we told the range() function how many integers we wanted in our list by passing the number ‘10’ as part of the function. In our flower drawing turtle program we called range() like this:

>>> range(36)
[0, 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]
>>>

This generated a list of 36 numbers, from 0 to 35. These two examples demonstrate that we can change what the range() function does based on the value we give to it. The value we give to the range() function is called a parameter, and the value of that parameter is used to change what the range() function does. In the examples above the parameter tells the range() function how many numbers to put in the list it generates and gives back to our program.

We’ve also used functions when we were working with our turtle. For example when I changed the color of my turtle t, with the color() function, like this:

>>> t.color("yellow", "red")
>>>

I was calling the color() function of the turtle variable t, and passed it two parameters, “yellow” and “red”. The “yellow” parameter changed the color of the t turtle and the color it draws with. The “red” parameter changed the color the turtle used when filling a shape.

Flower Drawing Using Functions

Okay, so it’s great that Python provides a bunch of functions we can use to do different things, how do functions help me be lazy? Well, Python also lets us create functions and use them just like we would any built in function. In Idle let’s open our turtle program code from last class and try something out. Modify your program to look like this:

import turtle

t1 = turtle.Turtle()
t1.shape("turtle")
t1.speed(0)
t1.color("yellow", "red")
t1.width(3)

def draw_box(t):
        t.begin_fill()
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.end_fill()

for petal in range(36):
        draw_box(t1)
        t1.right(10)

Save and run our program and it should create our flower exactly as it did before. You’re probably thinking “what’s the big deal, it did exactly the same thing”, and you’d be right!

Notice I renamed our turtle variable from t to t1. Why did I do this? I’m getting ready to draw with two turtles at the same time. Notice also the function I’ve defined draw_box has a t in between the parenthesis, and even though my turtle variable is defined as t1, I’m using a variable called t inside the draw_box function. The draw_box function is defined by beginning with the Python keyword def, followed by any word(s) we’d like, parenthesis and finally a colon character ‘:’.

Just like the range(36) function, where I pass it a value of 36 so it returns a list of 36 numbers, here I’m passing a parameter I’m calling t, and it’s using that to draw with. Inside my for loop notice that I’m calling draw_box with my newly renamed t1 variable. This is because the variable name passed to a function as a parameter has nothing to do with the variable name inside the function when it’s defined. Notice also that all the drawing code in the draw_box function is indented. Just like the for loop this indicates these Python statements are part of the function definition for draw_box().

New Turtle Drawing Functions

We’re getting ready to draw multiple flowers with multiple turtles. To do that and have them look good on the screen we’ll learn some more turtle drawing functions.

Turtle Pen Up

We can move our turtle without drawing a line as we go by lifting our pen up. In this way we can move the turtle and no line will be drawn. To do this we use the turtle penup() function. It looks like this:

t1.penup()

Turtle Pen Down

Once we’ve moved our turtle where we want it to be without drawing a line, we need to put the pen down again, and the turtle system allows for this. We use the pendown() function. It looks like this:

t1.pendown()

Turtle Goto

We can move our turtle to a specific position on the screen using the goto() funciton. We pass x and y coordinates to the goto() function to position our turtle. One thing to be aware of is the 0, 0 coordinates are where our turtle is created (center of the screen) when we did this “t1 = turtle.Turtle()”. So the coordinates we pass to goto() are relative to that starting position. The goto() function looks like this:

t1.goto(150, 150)

Let’s update our program and move our t1 turtle up and to the right a bit just to see how these new drawing functions work. Make your flower program look like this:

import turtle

t1 = turtle.Turtle()
t1.shape("turtle")
t1.speed(0)
t1.width(3)
t1.color("yellow", "red")

t1.penup()
t1.goto(150, 150)
t1.pendown()

def draw_box(t):
        t.begin_fill()
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.end_fill()

for petal in range(36):
        draw_box(t1)
        t1.right(10)

Save and run your program and you should see your flower, but it is offset up and to the right side of the screen by 150 pixels. Those are the offsets we passed as the first and second parameter to the t1.goto(150, 150) function call.

Drawing With Multiple Turtles

We want to draw with multiple turtles, and our goal for this class is to create this image:

_images/three_turtles.png

So far our flower drawing program is working pretty well, but can we change it even more to draw two, or perhaps more, flowers at once? Sure we can, we’re programmers! In order to use two turtles we’ll have to create a second turtle. I’m going to call the second turtle t2 just to stay consistent. Add this to your program right below where we created our first turtle t1:

t2 = turtle.Turtle()
t2.shape("turtle")
t2.color("blue", "orange")
t2.shape("turtle")
t2.speed(0)
t2.width(3)

This creates a second turtle with a different name, drawing color and fill color. When we create a turtle it’s starting position is right in the center of the screen, so our second turtle starts out right in the middle of the screen. Let’s move it left and down so t1 and t2 don’t draw on top of each other. Let’s add these lines for turtle t2 under the same lines for t1:

t2.penup()
t2.penup(-150, -150)
t2.pendown()

Houston We Have a Problem

At this point our program should look like this:

import turtle

t1 = turtle.Turtle()
t1.shape("turtle")
t1.speed(0)
t1.width(3)
t1.color("yellow", "red")

t2 = turtle.Turtle()
t2.shape("turtle")
t2.speed(0)
t2.width(3)
t2.color("blue", "orange")

t1.penup()
t1.goto(150, 150)
t1.pendown()

t2.penup()
t2.goto(-150, -150)
t2.pendown()

def draw_box(t):
        t.begin_fill()
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.end_fill()

for petal in range(36):
        draw_box(t1)
        t1.right(10)

If save our program and run it our turtle screen looks like this:

_images/two_turtles_one.png

Where’s The Second Flower?

When you get your program running you’ll notice the second turtle didn’t draw a flower. Why not? Well, we didn’t tell it to draw anything, so it just waited around while the first turtle drew a flower. How do we get it to draw it’s own flower? We add it to the for loop. Our updated program now looks like this:

import turtle

t1 = turtle.Turtle()
t1.shape("turtle")
t1.speed(0)
t1.width(3)
t1.color("yellow", "red")

t2 = turtle.Turtle()
t2.shape("turtle")
t2.speed(0)
t2.width(3)
t2.color("blue", "orange")

t1.penup()
t1.goto(150, 0)
t1.pendown()

t2.penup()
t2.goto(-150, 0)
t2.pendown()

def draw_box(t):
        t.begin_fill()
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.end_fill()

for petal in range(36):
        draw_box(t1)
        t1.right(10)

        draw_box(t2)
        t2.right(10)

Just by adding two lines we got our second turtle t2 to draw its own complete flower. This is a definite win for laziness, all we had to do was add a couple Python statements to draw a complete second flower! By setting things up and using a function we are able to build more and more interesting programs. In fact we could keep going and add more and more turtles to fill the screen with flowers and all we’d have to do is create more turtles and add statements to our for loop. But this is starting to look like when we were adding flower petals to start with. Can we be lazy and organize things differently to handle multiple turtles better? Yes of course, we can use something Python calls lists.

Lists

Lists are a way of grouping things together so we can work with them all at once. We’ve already seen lists because that’s what the range() function creates, lists of numbers. So for example the Python statement:

>>> range(5)
[0, 1, 2, 3, 4]
>>>

creates a list of 5 numbers. There’s nothing magical about this, we can create lists of our own just as easily. If we enter these statements in the interactive window:

>>> my_list = [4, 2, 3, 0]
>>> print my_list
[4, 2, 3, 0]
>>>

We created a variable we called my_list containing the list [4, 2, 3, 0]. You can see the things in the list don’t have to be in order. Lists are created by surrounding a set of things seperated by commas with the ‘[‘ and ‘]’ characters. We can use a list to organize our turtles. We can create a list of turtles like this in our program:

turtles = [t1, t2]

This creates a variable called turtles that is a list containing our two turtles. Now we can create a new for loop that gets a turtle from our turtles list and draws with it. We do this with these Python statements:

for a_turtle in turtles:
    draw_box(a_turtle)
    a_turtle.right(10)

We’re using a for loop to get each turtle one at a time from our turtles list, assigning it to the variable a_turtle and calling draw_box() and right(10) with that variable. If we put this inside our main for loop, it will be called for each petal the main for loop wants to draw.

We can now add a third turtle easily by creating a new turtle and adding it to the turtles list. Let’s do that in our updated, three turtle program. I’ve added comments to describe what’s going on:

import turtle

# create our t1 turtle
t1 = turtle.Turtle()
t1.shape("turtle")
t1.speed(0)
t1.width(3)
t1.color("yellow", "red")

# create our t2 turtle
t2 = turtle.Turtle()
t2.shape("turtle")
t2.speed(0)
t2.width(3)
t2.color("blue", "orange")

# create our t3 turtle
t3 = turtle.Turtle()
t3.shape("turtle")
t3.speed(0)
t3.width(3)
t3.color("red", "blue")

# move t1 to it's starting position
t1.penup()
t1.goto(150, 150)
t1.pendown()

# move t2 to it's starting position
t2.penup()
t2.goto(-150, -150)
t2.pendown()

# move t3 to it's starting position
t3.penup()
t3.goto(-150, 150)
t3.pendown()

# define our draw_box function
def draw_box(t):
        t.begin_fill()
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.forward(100)
        t.right(90)
        t.end_fill()

# create our list of turtles
turtles = [t1, t2, t3]

# create our for loop for 36 petals of the flower
for petal in range(36):

        # create our for loop to draw a flower petal with each turtle
        for a_turtle in turtles:

                # draw and rotate each turtle
                draw_box(a_turtle)
                a_turtle.right(10)

I created a third turtle called t3 and just added t3 to the turtles list. Notice that our main for loop didn’t change, as far as its concerned it’s just looping 36 times. The inner for loop is responsible for calling the draw_box() function with each turtle variable, and then turning that turtle right 10 degrees. Here’s what the output of the program looks like:

_images/three_turtles.png

Congratulations, you’re a multi-turtle genius now!!