Python Closure: How and Why to use
Closure in python is the function that remembers values in enclosing scopes even if they are not present in memory. In this article, we will discuss about python closure in detail with the help of examples.
In this article, we will be looking into the concept of python closures in detail. But to understand the concept of closures in Python we need to make ourselves familiar with the concept of Nested Functions.
Let’s get started with the Nested Function first.
Nested Functions in Python:
Whenever we define a function inside another function is called a nested function.
For instance, take a look at the below examples.
Example 1:
# enclosing outer# function definitiondef outer_function(test_string): # inner function definition def inner_function(): print(test_string) # calling inner_function() # within the outer_fun() # ie,nested function return inner_function()
# calling the outer_function()outer_function("Naukri")
Output:
Naukri
In the above example, we have defined a function called the outer_function(), which is the outer function within which the inner function namely, inner_function() is defined. Then we made a call for the inner function inside the scope of the outer function. Finally, we made a call to the outer function(ie, outer_function()), outside the scope of the outer function. The outer_function() takes a test_string as a paramere and the inner_function() just simply prints the parameter received by the outer_function(). In other words, we can say that the outer_function() is an enclosing function and the inner_function() a local function of the enclosing function.
As we can observe from the output, the outer_function() receives a test_string(ie, Naukri), and the inner function simply prints the test string received by the outer function as a parameter.
Must Read: What is Python?
Must check: Python Online Course and Certification
Let’s take one more example to better understand the concept of Nested Functions.
Example 2:
# function to pop last element# from a given list
# outer/enclosing functiondef pop(list): # inner function def get_last_item(my_list): # returns last element # from list received by the # outer function return my_list[len(list)-1] # remove the last element # from list list.remove(get_last_item(list)) # return list return list
# test_listtest_list = [1,2,3,4,5]
# pop 5 from listprint(pop(test_list))# pop 4 from listprint(pop(test_list))# pop 3 from listprint(pop(test_list))# pop 2 from listprint(pop(test_list))
Output:
[1, 2, 3, 4] [1, 2, 3] [1, 2] [1]
We have defined this pop() function which is our outer/enclosing function and then we have defined a function called get_last_item() which is our inner/local function to the pop function. Now, this pop() function takes the list as an argument. In the get_last_item() function, whenever you pass a list as an argument to this local function, it’s going to find out the last element of the list and return the last value of this list.
Now you may already know that you can call a function called () on your lists which is used to remove some items from the list. So we are just calling the remove() function on the list and as an argument of the list, we are passing the function which finds out the last element of the list. So the inner function is going to give us the last element of the list and then the last element will be removed from the list using the remove() function. Finally, we are simply returning the list which is passed as an argument to the pop function after removing the last element.
As you can observe in the output of the above function call that when the first pop is called it’s going to remove the last element which is 5 from the list and then whenever the second pop is called it’s going to remove the four and whenever the third pop method is called it’s going to remove the three and so on and so forth. This is how you can use nested functions in Python.
Must Read: Why use Python Datetime module?
Must Read: Free QR generator using Python
Now let’s talk about the closures in Python.
Best-suited Python courses for you
Learn Python with these high-rated online courses
Python Closures:
For the sake of simplicity while understanding the concept of closures, let’s bring back the example we used as example 1. So the below function as we know is a nested function.
# enclosing outer# function definitiondef outer_function(test_string): # inner function definition def inner_function(): print(test_string) # calling inner_function() # within the outer_fun() # without parentheses return inner_function
# calling the outer_function()outer_function("Naukri")
Output:
No Output
Now in order to convert this nested function into a closure, we need to return the inner function without the parentheses(ie, return inner_function() to return inner_function). So the thing to note here is we don’t need to return the inner_function() with the parentheses. This is the simplest example of closure.
A closure is a function whose return value depends on the value of one or more variables that are declared outside the function. So in the above example, this test_string variable is declared outside the inner function and the value of this inner function depends on that variable. This makes it a closure.
Must Read: Pattern Program in Python
Must Read: Type Conversion in Python
The closure has a special property that the closure function object remembers the value in the enclosing scope even if they are not present in the memory.
So to use this outer function which now uses closure, we need to treat the outer function as a Python object. And that object holds the inner function within it. for this we need to declare a variable x as shown below:
x = outer_function("Naukri")
At this point our example code looks like the below:
# enclosing outer# function definitiondef outer_function(test_string): # inner function definition def inner_function(): print(test_string) # calling inner_function() # within the outer_fun() # without parentheses return inner_function
# treat the outer_function() as objectx = outer_function("Naukri")
# call function objectx()
Output:
Naukri
So in order to use this x as the function, we can just call the x using the parentheses because this function doesn’t take any arguments. We are not passing any argument inside x, but we will just call it as a function because this outer function is just returning the inner function.
As we discussed above, a closure is a function object that remembers the value in the enclosing scope even if they are not present in the memory. So our enclosing scope is the outer function, therefore even if we delete the outer function after declaring the statement and if the x variable contains the inner function then and at this point, the system will still work for x.
Must Read: Comparison Operator in Python
Must Read: Memory Management in Python
For example, let’s just delete the outer function using the del keyword and call the outer function again as shown below:
Example 1:
# enclosing outer# function definitiondef outer_function(test_string): # inner function definition def inner_function(): print(test_string) # calling inner_function() # within the outer_fun() # without parentheses return inner_function
# treat the outer_function() as objectx = outer_function("Naukri")
# delete the outer functiondel outer_function
outer_function("Naukri")
# call function objectx()
Output:
As we can see in the above output that the program throws us an error stating that the function (ie, outer_function()) does not exist.
Now comes the interesting part, if we now just make a call to x(), it will return us a valid output even if the outer_function() gets deleted. Take a look at the below program for reference:
# enclosing outer# function definitiondef outer_function(test_string): # inner function definition def inner_function(): print(test_string) # calling inner_function() # within the outer_fun() # without parentheses return inner_function
# treat the outer_function() as objectx = outer_function("Naukri")
# delete the outer functiondel outer_function
# call function objectx()
Output:
Naukri
The above code works because we have already stored the value of the inner function in the variable x before deleting the outer_function(). This is the magic of closures in python.
A closure function is able to remember the values which are declared outside the function. Now let’s take one more example of the closure so we will be able to understand it in a better way.
Example 2:
# enclosing outer# function definitiondef nth_power(exponent): # inner function definition def pow_of(base): return pow(base,exponent) return pow_of
In the above example, we have defined a function called nth_power() and we pass one argument in it, which is an exponent. Inside this nth_power() function, we have defined a local function that also takes one argument(ie, base) and then it returns the power of whatever argument we pass to the pow_of() function, and the value of the exponent is coming from the outer scope, ie, this parameter is passed to the outer function(ie, nth_power()). Finally, we are returning the pow_of function without any parenthesis.
Now let’s declare a variable called square, that contains the value of the nth_power function. We will pass 3(ie, the exponent) as an argument to the nth_power() function. Then we will just print the value the square function and pass 5(ie, base) as an argument to it. The code would look like the below:
# enclosing outer# function definitiondef nth_power(exponent): # inner function definition def pow_of(base): return pow(base,exponent) # calling inner function # within the outer function # without parentheses return pow_of
# treat the outer function as objectsquare = nth_power(3)
# calling the function objectprint(square(5))
Output:
125
As we can see in the output, we used the square function object to find the 3rd exponent of base 5, meaning 5^3 = 5*5*5= 125. So it gave us the cube of 5. The square variable is holding the status of the inner function. This phenomenon can be observed in Python classes. The classes are able to remember the state of the variables and the methods which are declared inside the classes.
Must Read: Python if-else statement
Must Read: Abstraction in Python
Conclusion:
So closures are sometimes used in place of the classes which usually have only one method inside them. So closures can be used in place of the classes which have fewer methods generally one method inside them. The closure can have the following advantages:
- We can avoid the use of global values by calling the local function outside its scope, and accessing the enclosed variable outside its scope.
- It is great for hiding data in your programs and is highly used while building python microservices.
- It is used for implementing decorators in Python.
This is a collection of insightful articles from domain experts in the fields of Cloud Computing, DevOps, AWS, Data Science, Machine Learning, AI, and Natural Language Processing. The range of topics caters to upski... Read Full Bio