Introduction to Closures in Python
Proficiency: Beginner to Intermediate; I’m going to assume that closures are confusing to you.
Specifications: I’m using Python 2.7.6
In your shell, navigate to a directory where you can make some sample code files.
If you don’t have one that you already use for this purpose, make a directory called closure_practice
and navigate into that directory:
cd ~
mkdir closure_practice
cd closure_practice
I’ve added this next section in my latest draft of this post, because I realized that it’s important that you understand two things before we start on closures.
Exercise 0.1: Functions stored in variables
This is a thing that can happen in Python:
def say_hi_to_reed():
print("Hi Reed")
say_hi_to_reed() # => "Hi Reed"
variable_holding_a_function = say_hi_to_reed
variable_holding_a_function() # => "Hi Reed"
Exercise 0.2: Functions defined inside another function
This is another thing that can happen in Python:
def say_hi():
def provide_name():
return "Reed"
name = provide_name()
print "Hi {}".format(name)
say_hi()
Make sure you understand how say_hi
constructs its output string from the function provide_name
that is defined within it.
Exercise 1: Intro to Closures
Create a file (inside of the directory we mentioned above) called exercise1.py and open it up in the editor of your choice (I use Sublime Text). Here’s what I did:
touch exercise1.py
subl exercise1.py # Note: subl is Sublime Text's shorthand to open things up into it
Let’s say that we want to make a function that takes a number x
and returns the value of multiplying that number by 10.
In closure_practice/exercise1.py
:
def times_ten(x):
return x * 10
result = times_ten(5)
print(result)
In your shell, run it:
python exercise1.py
50
So far so good. Now let’s make a function that takes two numbers x
and y
, and returns their product.
Back inside closure_practice/exercise1.py
:
def multiply(x, y):
return x * y
result = multiply(5, 10)
print(result)
In your shell:
python exercise1.py
50
Right, so comment all of that out, and it’s on to the next one. (I recommend commenting out, rather than deleting these early portions, so that you have them to refer to in the same file.)
Closures:
What if we want to make a function times
that takes a number x
, and which returns a function that itself takes a number y
, and this function returns the value of multiplying x
and y
?
Let’s step through this by breaking that down:
- Make a function
times
that takes a numberx
:
def times(x):
pass
- Which returns a function that itself takes a number
y
…
def times(x):
def multiply(y):
pass
return multiply
- And this function returns the value of multiplying
x
andy
:
def times(x):
def multiply(y):
return x * y
return multiply
This is an example of a closure. A closure describes the relationship the inner function multiply
has to its parent function times
. It includes the dependence multiply
has on times
to fulfill the lexical scope requirements of its calculations – (times
provides multiply
with x
).
I’m going to go into more depth in this in a later post.
Remember our times_ten
function above? It took a number x
and returned the value of multiplying x
and 10
.
With our new closure function times
, we can remake the function times_ten
.
Note: The advantage doing this is reffered to as function portability, or making higher order functions, or more generally abstraction.
Back inside closure_practice/exercise1.py
:
# The closure function from above
def times(x):
def multiply(y):
return x * y
return multiply
times_ten = times(10) # Can you explain what this sets times_ten to?
result = times_ten(5) # This is the code from the top of exercise1.py
print(result)
Go to your shell and run it:
python exercise1.py
50
Explaining what is happening
The key for my understanding this – when things really clicked for me – was realizing what return
is doing at each step.
Before writing this, I went through these exercises with a peer of mine, and this was where he was struggling also. This leads me to believe others will struggle with this too.
Back to the code. Follow the return
calls:
# The closure function
def times(x):
def multiply(y):
return x * y # When multiply is called, this is what it returns
return multiply # When times is called, this is what it returns
Then we set…
times_ten = times(10)
What is this doing? It is setting the variable times_ten
to the return value of calling times(10)
.
What is that return value; what does the function times
return? It returns the function multiply
.
Then, what does the function multiply
return? It returns the value of multiplying x
by y
.
Go back and track where, and at what point this closure receives the values of x
and y
.
When we say…
times_ten = times(10)
We are setting times_ten
to a function (multiply
) that itself takes a parameter y
, and which returns the value of x * y
.
If you go back to the top of your exercise1.py
file, and look at the code we commented out, you’ll that’s exactly what we did to times_ten
. We simply defined it as a function with the name times_ten
.
Closures provide us with an additional layer of abstraction. Now, instead of defining a function times_ten
, double
and triple
, we can use our closure function from above, and simply declare:
times_ten = times(10)
double = times(2)
triple = times(3)
print(times_ten(5)) # => 50
print(double(5)) # => 10
print(triple(5)) # => 15
Exercise 2: Try it on your own
touch exercise2.py
subl exercise2.py # The editor of your choice
Your challenge:
Inside closure_practice/exercise2.py
, try to make a closure function exponent
that takes a number y
, and which returns a function that itself takes a number x
, and which returns the value of raising x
to the power of y
.
First, you should try to make it work on your own. If you get stuck, I’m going to give hints and work through this as we proceed. If at any point you think that you can figure it out on your own, stopping reading and go try it.
If you’re not sure where to begin, start by breaking it down into the chunks like we did above:
- Make a closure function
exponent
that takes a numbery
- Which returns a function that takes a number
x
- This function returns the value of raising
x
to the power ofy
If that doesn’t help, here is how I would follow these steps:
One:
def exponent(y):
pass
Two:
def exponent(y):
def base(x):
pass
return base
Three (the solution):
def exponent(y):
def base(x):
return x**y
return base
How do you use this closure function to make a function called square
, that will return the value of squaring a number you give it?
How would you use your closure to make a cube
function, that cubes a number you give it?
My solutions, using the closure function above:
square = exponent(2)
cube = exponent(3)
Looking at what I just typed, what is square
after I declare…?
square = exponent(2)
Do you understand what square
is at that moment? Can you track through your code, and point to what you’re setting it to?
To make sure that you’ve got good answers to these questions:
square
becomes the function base
from our closure function, except that it has a value for y
(2). To spell that out with code, when we say square = exponent(2)
, it is the same as saying:
def square(x):
return x**2
Exercise 3: Interpreting someone else’s closure
Try to work through the following closure on your own. Use the tactics we used above.
def supply_x(x):
def unnamed_function(func):
return func(x)
return unnamed_function
supply_five = supply_x(5)
- Can you write a simple example that puts
supply_five
to use? - Can you make an example that uses
supply_x
with something other than a number, and then puts that to use? - With the first two examples, I started with instructions, “Write a function that take a number, and which returns a function…” Can you write what the instructions for the above closure would be?
If you can do these things, I think you’ve got the hang of closures.
I haven’t written it yet, but my next post will be on anonymous functions, and I’ll revisit this example when I write that.
If you’re confused, don’t worry. It’s confusing.
To start working out the confusing parts, try to answer these questions:
- After that last line, to what is
supply_five
set? Work backwards from there. - What is each function returning?
- What are the parameters of each function; what does each function require be passed in?
- Where and when are the parameters of the functions being used?
Spoiler ahead:
If you’re still confused, I want to walk you through it. Here’s the code again for reference:
def supply_x(x):
def unnamed_function(func):
return func(x)
return unnamed_function
supply_five = supply_x(5)
Answering the above questions:
supply_five
is set to the return value of callingsupply_x(5)
supply_x
returnsunnamed_function
- Okay, then what is
unnamed_function
? It is a function that takesfunc
as a parameter, and returnsfunc(x)
That’s strange, because we don’t explicitly know what func
is.
We can deduce what it is, though, right? It’s called func
, which isn’t meant to trick you. It’s probably a function. And the return value func(x)
reinforces that. We call functions with parenthesis, passing in their parameters as required.
You may feel that the code above assumes too much. You’re right, it does. As an exercise, though, once you understand what each part does and needs, it isn’t too hard to make an example that puts supply_x
to use.
Before I say more, see if you can put supply_x
to use. Feel free to use supply_five
.
Returning to the explanation:
supply_x
returnsunnamed_function
unnamed_function
takes the parameterfunc
, and returns the value of callingfunc(x)
.
This feels strange, because we don’t know what func
might be. Okay, but what do we know? We know that we can pass unnamed_function
a function, and it will return the value of calling the function we passed into it with the value of x
.
If we say supply_five = supply_x(5)
, then supply_five
will call whatever function it is given with 5 as the parameter.
How do we put this to use?
Let’s make a function that takes in a number, and returns the value of doing something with that number.
Go to closure_practice/exercise3.py
and add the above code if you haven’t already:
def supply_x(x):
def unnamed_function(func):
return func(x)
return unnamed_function
supply_five = supply_x(5)
# We make something that can use supply_five
def multiply_by_ten(x):
return x * 10
# Now we use supply_five
test_result = supply_five(multiply_by_ten)
print test_result
Run the code:
python exercise3.py
50
Now go back to the closure, and write an example like the one above that uses a string instead of a number.
If you’re still confused, let me know and I’ll work with you to make this post better.
Final comments
I’m left feeling that I’ve spent all of the above time focusing on useless examples, not teaching anything useful. This is partly (or mostly) because I am new to all of this myself, and I don’t know enough to appreciate the power of these tools.
That said, I do know that, conceptually, the reason closures are powerful is because of the additional layer of abstraction they grant us. I’ve heard this called “higher-order functions”.
I hope that makes sense, conceptually. We can make a function that takes a number and multiplies it by ten. Or we can make a function that lets us create other functions to accomplish various aspects of a given task.
I will revisit and update this as I learn more. In the meantime, I’ve learned more by looking at:
Further reading:
- Closures Part II: Anonymous Functions
- http://stackoverflow.com/questions/36636/what-is-a-closure
- Mozilla’s post about closures (in JavaScript)
- The 10 Most Common Mistakes That Python Developers Make, check out Common Mistake #6: Confusing how Python binds variables in closures
- My friend’s Closure practice in Ruby
- Read the chapter “First Class Functions” in this article