Skip to content

8 min read

American Corners

Functions and scope

We have used functions all along

A function is a small, named piece of a program that solves one specific sub-problem. You have been using them since the first lesson, probably without noticing.

Think about the lines you have already written:

  • len(mystring) hands back the length of a string.
  • turtle.forward(100) moves the robot forward.
  • print(s1) types a value to the screen.

Each of these is a function doing a job for you. You did not write the code that counts characters or moves the turtle; you just called the function by its name and let it do the work. That is the whole point of a function: give a useful piece of work a name, then reuse it whenever you need it, without repeating yourself.

So far you have only been calling functions that Python or the turtle library already wrote. Now you will write your own.

Making your own function

You create a function with the word def, which is short for "define". You give it a name, list any inputs it needs, and indent the code that belongs to it.

def my_function(arg1, arg2):
    """Write a short description of what this function does."""
    # your code goes here
    return some_value

There are a few parts worth naming:

  • The name (my_function) is how you will call it later.
  • The arguments (arg1, arg2) are the inputs. An argument is a value you pass in so the function can work with it. A function can take no arguments, one, or many.
  • The line in triple quotes is a docstring, a short note describing what the function does. It is optional but kind to your future self.
  • return hands a value back to whoever called the function. You can return a number, a string, a list, anything.

Defining a function does not run it. The code inside only runs when you call it by name:

def add(a, b):
    """Return the sum of two numbers."""
    return a + b

total = add(3, 5)
print(total)   # 8

Here add(3, 5) calls the function with the arguments 3 and 5. The function returns 8, and we store that in total. If you define a function but never call it, the code inside it simply never runs.

A worked example: drawing shapes

Functions really pay off when one function calls another. Let us build a shape drawer step by step.

First, a function that draws any regular polygon. To draw a shape with num_sides equal sides, the turtle turns by 360 / num_sides degrees at each corner: 120 degrees for a triangle, 90 for a square, and so on.

import turtle

def draw_shape(length, num_sides):
    """Draw a regular polygon with the given side length and number of sides."""
    angle = 360 / num_sides
    for side in range(num_sides):
        turtle.forward(length)
        turtle.right(angle)

Now draw_shape(100, 3) draws a triangle and draw_shape(80, 4) draws a square. One function, many shapes.

Next, a function that uses the first one to draw ten squares, each a little larger than the last:

def draw_increasing_squares():
    """Draw 10 squares, each 10 steps longer than the one before."""
    length = 50
    for i in range(10):
        draw_shape(length, 4)
        length = length + 10

draw_increasing_squares()

Notice that draw_increasing_squares does not know how to draw a square itself. It hands that job to draw_shape. Each function does one clear thing, and the bigger job is built from the smaller ones. That is how real programs stay readable as they grow.

Lab

Try it: call draw_increasing_squares() once, then turn the turtle right by 10 degrees and call it again. Repeat inside a loop to fan the squares into a full circle. How many turns of 10 degrees make one full turn?

Where a variable lives: scope

When you create a variable inside a function, it belongs to that function only. This is called its scope. Once the function finishes, the variable is gone. Code outside cannot see it.

def greet():
    message = "Hello from inside"   # a local variable
    print(message)

greet()
print(message)   # error: message is not defined out here

The variable message is local to greet. The first print works, because it runs inside the function. The second one fails, because outside the function message does not exist.

A variable created at the top level of your program, outside any function, is global. Functions can read a global value, but a name you make inside a function stays inside it:

angle = 90            # global

def show_angle():
    print(angle)      # can read the global value

show_angle()          # prints 90

This is a good thing, not a limitation. Because each function keeps its own variables to itself, you can reuse a plain name like length or i in many functions without them clashing. If you want a value to travel out of a function, pass it in as an argument or hand it back with return, rather than relying on shared names.

Check yourself

  1. What is the difference between defining a function and calling it? What happens if you define a function but never call it?
  2. In draw_shape(length, num_sides), what are length and num_sides called, and why does draw_increasing_squares not need to know how to draw a square itself?
  3. If a variable is created inside a function, can code outside that function use it? How would you get a value out of a function so the rest of your program can use it?

Where this lesson comes from

Built from

  • Programming in a Data World: Lecture 4 deck (Functions) and Lecture Notebook
  • Video: 4.0 Functions

alphaPlan courses are built from taught programmes rather than invented for the web. Where a claim rests on an outside standard or a reported case, it is named above so you can check it rather than take our word for it.

This course was developed by alphaPlan Center from programs delivered in partnership with the American Corners network.

Found something unclear, outdated or improvable? Suggest an improvement