Using Functions as Return Values: Closures
For more information on topics covered in this lesson, check out these resources:
00:00
In this lesson, we’ll explore how and why you might use a function as a return value. In Python, functions are considered first-class objects. This means they can be assigned to a variable, used as an argument to a function, or used as the return value of a function. Here, specifically, this means that we can use a function object as the return value in any return
statement. A function that returns a function or takes a function as a parameter is referred to as a higher-order function.
00:35 A closure factory function is an example of a higher-order function. This type of function takes an argument and returns an inner function. This inner function is usually known as a closure.
00:52 A closure carries information about its enclosing execution scope. This provides a way for a function to keep track of its state information between function calls. Closure factory functions are useful when you need to write code based on the concept of lazy or delayed evaluation. As an example, suppose you want to write a function that takes a single number and provides the result of multiplying that number by a specific factor.
01:23
Say you always want to multiply a number by 2
, or another function that always multiplies a number by 7
, and so on. In this context, the value of the factor is going to be the same for a series of runs of this function. Here is a simple example, but it takes two arguments and doesn’t take into account that one of them, factor
, isn’t going to change much. Let’s do a little bit better.
01:51
This other function uses a closure to retain the value of factor
between function calls. Inside by_factor()
is an inner function called multiply()
, which is created and returned without being called.
02:09
The function object returned is a closure that retains information about the factor
being used. When you give a value for factor
, by_factor()
returns a function that knows to multiply its only parameter number
by the factor
provided as an argument when by_factor()
was called.
02:35 Here are a couple of examples of how we might use it.
02:41
We’re going to create a function called double()
, which uses by_factor()
to give us a function which always multiplies by 2
.
02:53
So by_factor()
returned for us a function that’s going to multiply a single parameter by 2
. When we call double()
with an argument, it essentially calls multiply()
using 2
for factor
and whatever number was provided for the parameter number
.
03:18
Similarly, we can create a function triple()
,
03:25
which always uses 3
for the factor
in multiply()
.
03:31
So if I triple 3
, I get 9
, and if I triple 4
, I get 12
. double()
remembers that factor
was 2
and triple()
remembers that factor
was 3
.
03:47
You can also use lambdas to create closures. This often provides a more concise version of your closure factory. For example, we just returned the lambda which takes the number and multiplies it by the argument provided in factor
when by_factor()
creates the function.
04:07
So by_factor()
takes a factor
and it returns for us a function defined as a lambda
, which takes a number
and multiplies that number
by the factor
provided when this lambda
is created.
04:26
Again, I can create a double()
method, which calls by_factor()
with the argument of 2
, and it returns a function that takes a number
and multiplies and returns that number
multiplied by this factor
2
we’re providing it.
04:43
So again, double(3)
gives us 6
, double(4)
gives us 8
, and we could define triple()
and observe the same results we did before.
04:56 For more information about inner functions, generators, lambdas, and anything else from this lesson, please check out the links below the video. Next, we’ll look at using decorators to write functions that take and return functions.
Become a Member to join the conversation.