8 min read
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.
returnhands 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
- What is the difference between defining a function and calling it? What happens if you define a function but never call it?
- In
draw_shape(length, num_sides), what arelengthandnum_sidescalled, and why doesdraw_increasing_squaresnot need to know how to draw a square itself? - 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