Back to Table of Contents

Skip to Reading Quiz

Skip to Exercises

Turtle Graphics (Functions)

This is the last of the Turtle Graphics readings. It will teach you how to define your own commands, or functions.

When you create your own command or function, you are capturing pieces of your program for later use. When you do this, you avoid having to write the same code multiple times. Instead, each time you want Python to execute a particular sequence, you simply invoke the name of the function you created. Python will then refer to a place in your program where you wrote that sequence.

Functions, like for loops, help you to follow the principle "don't repeat yourself" (DRY).

If you'd like to follow along, open the following URL in a separate tab or window:

https://repl.it/languages/python_turtle

I would recommend making an account on REPL if you haven't already, so you can save your code and revisit it later.

Motivation

In the last reading, you saw how a for loop can be used to reduce the length and redundancy of code. In order for a for loop to be effective, the repetitive portion of a program must occur back-to-back-to-back, like this:

forward(50)
backward(50)
left(90)
forward(50)
backward(50)
left(90)
forward(50)
backward(50)
left(90)
forward(50)
backward(50)
left(90)

Now, suppose you have a piece of code that happens more than once in a program, but those occurrences are not next to each other. Say, for example, that you are writing a program, and you occasionally want to draw a small square, like this:

Just an image of the result of a program (no code). It is a black square with edges of length 20 and with the arrow facing right. The arrow's tip is at the bottom left corner of the square. The arrow is black.

Perhaps the larger picture you are trying to draw might look something like this:

This is also just the result of a program. The image contains a square with sides of length 20. It has a line segment of length 30 going to the right starting at the bottom right corner of the square. There is then a line segment of length 40 going down from the right end of the most recent line segment. Finally, there are four squares, all with sides of length 20. Three of them are in a vertical stack, with the upper left corner of the topmost one being at the same point as the bottom end of the 40-pixel line segment mentioned earlier. The fourth square's left edge lines up with the right edge of the square in the middle of the stack of three. The arrow is facing upwards, and its tip is on the upper left corner of the fourth square. The arrow and all lines and squares are black.

Since the squares in this drawing aren't made immediately after one another, we cannot simply use a for loop to repeat the segment of code that draws a single square. What we can do instead is create a command that draws a square and invoke that command each time we need a square drawn.

What is a Function?

The technical term for a command in Python is a function. Every time you've used forward and backward, for example, you've actually been using functions called forward and backward. Invoking a function by using its name in your program is known as calling the function.

When you call the forward function, for example, there are a number of things Python must do to respond to this function call: it must compute the arrow's new location based on the distance (provided in parentheses) and the arrow's current direction, make note of the fact that there may be a new line segment on the screen, and update the result window to display everything that has happened. The code that makes all this happen is hidden from you, but take on faith that some amount of code must be executed in order for all this to happen. Instead of making you write that code every time you want to move forward, Python keeps it all locked in a function called forward. Whenever you call the forward function, Python knows to go and execute the other code needed to make the arrow move forward. In this way, a function can be thought of as an alias for another section of code.

Making Your Own Function

The main concepts in this module will become more clear when you start making your own functions. Let's start with a simple example: say we want to make a new function called forward_backward_twenty. As the name suggests, calling this function will cause the arrow to move forward 20 and then backward 20.

We can create the function like this:

from turtle import *

def forward_backward_twenty():
forward(20)
backward(20)

The first unfamiliar part of this is syntax is the word def. It is short for define, and it indicates that you are about to define a new function. Function definitions in Python always start with def. def is then immediately followed by the function name, a pair of parentheses, and a colon. (Later, we will learn when it is appropriate to put things in the parentheses.)

Everything after the definition line that has been indented is considered to be in the function (or part of the function body). In this way, a function definition is similar to a for loop. Like with a for loop, with a function definition, the indentation must be uniform. Anything that is not indented is treated as outside the function body.

Note that the program above doesn't actually do anything; that is, it doesn't have any effect on the arrow. By defining the function, we are merely teaching Python what forward_backward_twenty means. We are not actually asking Python to execute forward_backward_twenty. In more technical terms, we are defining the new function, but we have yet to call that function.

Let's add some function calls to the program:

from turtle import *

def forward_backward_twenty():
forward(20)
backward(20)

forward_backward_twenty()
left(90)
forward_backward_twenty()

The left side of the REPL window contains the code written above this image. The right side contains the result. There are two black 20-pixel line segments extending to the right of the origin and upwards from the origin. The arrow is black and facing upwards, and its tip is on the origin.

The last three lines of the program above actually cause the arrow to do something. Once forward_backward_twenty has been defined, it can be used just like any other command.

If we did not have the ability to define functions in Python, the above program would have to be written like this:

from turtle import *

forward(20)
backward(20)
left(90)
forward(20)
backward(20)

Notice the two identical segments of code. Since they are not adjacent, we cannot use a for loop to condense the program. By creating a function that contains the two repeated lines, we only have to write the two-line sequence once, and it can be re-used whenever we need the arrow to move forwards and backwards by 20.

Examples

Squares

Here is a program that makes a function called draw_square and uses it to make the picture shown at the beginning of this reading:

from turtle import *

def draw_square():
    forward(20)
    left(90)
    forward(20)
    left(90)
    forward(20)
    left(90)
    forward(20)
    left(90)

draw_square()
forward(50)
right(90)
forward(100)
draw_square()
left(90)
forward(20)
draw_square()
left(90)
forward(20)
draw_square()

The left side of the REPL window has the code written above this image. The right side is the result, which is the same as the image presented earlier in this reading with multiple small squares. The image contains a square with sides of length 20. It has a line segment of length 30 going to the right starting at the bottom right corner of the square. There is then a line segment of length 40 going down from the right end of the most recent line segment. Finally, there are four squares, all with sides of length 20. Three of them are in a vertical stack, with the upper left corner of the topmost one being at the same point as the bottom end of the 40-pixel line segment mentioned earlier. The fourth square's left edge lines up with the right edge of the square in the middle of the stack of three. The arrow is facing upwards, and its tip is on the upper left corner of the fourth square. The arrow and all lines and squares are black.

This program can actually be condensed even further. Notice the repetition in the code within the function:

def draw_square():
    forward(20)
    left(90)
    forward(20)
    left(90)
    forward(20)
    left(90)
    forward(20)
    left(90)

We can actually turn this into a for loop! Since this for loop is inside the body of a function, the body of the for loop will have to be indented by two levels:

def draw_square():
for i in range(4):
forward(20)
left(90)

Here is the whole program, with the for loop within the function:

from turtle import *

def draw_square():
    for i in range(4):
        forward(20)
        left(90)

draw_square()
forward(50)
right(90)
forward(100)
draw_square()
left(90)
forward(20)
draw_square()
left(90)
forward(20)
draw_square()

The blank lines do not actually serve any functional purpose. They just make the program more readable. You could have a less readable but still functionally correct program like this:

from turtle import *
def draw_square():
for i in range(4): forward(20)
left(90) draw_square() forward(50) right(90) forward(100)
draw_square() left(90) forward(20) draw_square() left(90) forward(20) draw_square()

In the above version, blank lines are placed haphazardly in the program. This is bad programming style, but the program will still work. Blank lines do not determine what is considered part of a for loop or part of a function. Python only pays attention to indentation when determining those things.

Plus Sign

Here is a program that uses our forward_backward_twenty function to draw a plus sign:

from turtle import *

def forward_backward_twenty():
forward(20)
backward(20)

forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)

The left side of the REPL window contains the program above. The right side is on the result tab. There is a black plus sign with branches of length 20 centered at the origin. The arrow is black and facing to the right, with its tip at the origin.

This program can also be further condensed. Note the repetition:

from turtle import *

def forward_backward_twenty():
    forward(20)
    backward(20)

forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)
forward_backward_twenty()
left(90)

Calls to custom functions, like forward_backward_twenty, can be put in for loops just like other function calls:

from turtle import *

def forward_backward_twenty():
    forward(20)
    backward(20)

for i in range(4):
    forward_backward_twenty()
    left(90)

Some Final Thoughts

The theme of the last couple modules has been using Python programming constructs to avoid repetition. Now that you know how to use these constructs - for loops and function definitions - you should do your best to avoid repetition in your code. If you ever find yourself copying and pasting code, stop and ask yourself whether there is a way to condense what you are trying to write.

Dividing your program into functions is also a good way to follow the programming practice of modularity - dividing your program into small, well-defined pieces. Modularity has a few benefits. First, it helps you not repeat yourself (making alterations and maintenance easier). Second, it helps you isolate problems more quickly. It is easier to test several well-defined units by themselves than to test one large system as a whole. Third, it helps you logically divide the problem you are trying to solve into pieces, which in turn helps you stay mentally organized as you try to solve the problem. As you continue to program, the programs you write will be come more and more complicated, and thus more and more difficult to keep in your head all at once. Dividing a program into pieces allows you to concentrate on specific parts of a program without having to simultaneously consider the entire rest of the program.

Reading Quiz

Back to Top

1. Which of the following is least true about creating your own functions?

a.

By creating your own functions, you are creating an alias for a segment of code.

b.

Creating your own functions allows you to reuse code that might otherwise have to be written multiple times.

c.

By creating your own functions, you can draw pictures with Turtle Graphics that would not be possible to draw without creating your own functions.

d.

Creating your own functions can make your code more organized and easy to keep track of.

2. Which of the following lines correctly defines a new function called turn_around?

a.
func(turn_around):
b.
define turn_around:
c.
def turn_around():
d.
function turn_around():

3. Suppose you have defined the function forward_backward_twenty from the reading. What would the following code do?

for i in range(4):
    forward_backward_twenty()
    left(180)
    forward_backward_twenty()
    left(180)
a.

It draws a line segment of length 160 going to the right from the origin.

b.

It repeatedly draws over the same line segment, extending 20 pixels to either side of the origin.

c.

It draws an octagon with edges of length 20 whose bottom left corner is at the origin.

d.

It draws a square with edges of length 20 whose bottom left corner is at the origin.

Exercises

Back to Top

For each of these exercises, you should start by creating a new Turtle Graphics REPL session. You can do this by going to:

https://repl.it/languages/python_turtle

Exercise 2.0

This program tries to draw a triangle using a function to draw each edge. See if you can fix it!

from turtle import *

def draw_edge():
forward(50)
left(120)

for i in range(3):
draw_edge()

When you are finished, your program should draw this:

A black triangle with sides of length 50 and with a bottom left corner at the origin and a bottom edge parallel with the bottom edge of the screen. The arrow is black and is facing right at the origin.

Exercise 2.1

This program tries to draw a hexagon with edges that alternate between green and blue. Currently, it draws the hexagon twice. See if you can fix it! Hint: the draw_two_edges function should only draw two edges, and currently, it doesn't.

from turtle import *

def draw_two_edges():
    for i in range(2):
        color('green')
        forward(50)
        left(60)
        color('blue')
        forward(50)
        left(60)

for i in range(3):
    draw_two_edges()

When you are finished, the program should still look like this but should only have drawn the hexagon once:

A hexagon with sides of length 50. The bottom left corner is at the origin, and the bottom edge is parallel with the bottom of the screen. The bottom edge is green, and the edges alternate between green and blue. The arrow is blue and is at the origin facing right.

Exercise 2.2

Write a Turtle Graphics program that defines the forward_backward_twenty function from the reading. Use this function to draw a five-pointed star with branches of length 50. You should begin by turning left by 90 degrees, so the first branch of the star extends upwards. Each branch thereafter is separated by the last branch by 72 degrees. Your arrow should finish facing upwards.

When you are finished with your program, it should draw this:

Five black edges of length 20 extending outwards from the origin. There is a 72 degree angle between each neighboring pair of edges. One edge extends directly upwards. The arrow is at the origin facing upwards.

Exercise 2.3

Write a Turtle Graphics program with a function called draw_red_line. This function should change color to red and draw a line segment of length 50 in whatever direction the arrow is currently facing. Don't worry about changing the arrow's color back after you've changed it to red.

You may write code beneath your function to test it. However, when you submit, you should not have any code in your program except your function! The test will add code to your program to make sure your function was written correctly.

Say you call your function like this:

forward(50)
draw_red_line()
left(90)
draw_red_line()

Your program should then draw this:

A black line of length 50 extending to the right from the origin. A red line of length 50 extending to the right, starting at the rightmost point of the black line. A red line of length 50 extending upwards, starting at the rightmost point of the other red line. The arrow is red and is at the topmost point of the last red line, facing upwards.

Exercise 2.4

Write a Turtle Graphics program with a function called draw_red_square. This function should:

You should not change the arrow's color back after you've changed it to red.

You may write code beneath your function to test it. However, when you submit, you should not have any code in your program except your function! The test will add code to your program to make sure your function was written correctly.

Say you called your function like this:

left(90)
forward(50)
draw_red_square()
forward(100)

Your program should then draw this:

A black line of length 50 extending upwards from the origin. A red square with edges of length 50 whose bottom right corner is at the topmost point of the black line and whose bottom edge is parallel with the bottom of the screen. A red line segment of length 50 extending upwards from the top right corner of the square. The arrow is red and is facing upwards at the top of the last line.

Exercise 2.5

Write a Turtle Graphics program with two functions - one called draw_edge and one called draw_corner_piece. You will use these functions to draw the square with corner decorations from a previous exercise.

The draw_corner_piece function should start assuming that the arrow has just drawn the edge of a square. It should turn the arrow the necessary number of degrees to draw a line segment of length 20 diagonally outwards from the corner that will form between the edge just drawn and the edge about to be drawn. It should then draw the line segment and position the arrow to draw the next edge of the square.

To make that less confusing, pretend that the arrow has just drawn the first edge of a square. It is 50 pixels to the right of the origin and facing right. If you were to call the draw_corner_piece function immediately after, this should be the result:

A black line of length 50 extending to the right from the origin. A black line of length 20 extending diagonally downward and to the right at a 135 degree angle from the first line and starting at the rightmost point of the first line. The arrow is at the rightmost point of the first line, is black, and is facing upwards.

You should copy the draw_edge function from here:

def draw_edge():
forward(50)
draw_corner_piece()

Note that the draw_edge function calls the draw_corner_piece function.

Now, in the main part of your program below your function definitions, use only the draw_edge function to draw a full square with four corner pieces, starting at the origin. The bottom left corner of the square (not including the corner decorations) should be at the origin. The arrow should end up at the origin facing right.

When you are finished, your program should draw this:

A black square with sides of length 50 and with its bottom left corner at the origin. From each corner, there is a line segment of length 20 extending outwards diagonally such that it makes a 135 degree angle with either adjacent square edge. The arrow is black and is facing right with its tip at the origin.

Back to Top

Back to Table of Contents