Closures in Python – A Practical Reference

Closures In Python

In this tutorial, we will see what are closures in Python, when do they exist and how do we use them.

To understand the concept of closures, we need to understand some basic concepts like nested functions and free variables.

Then we will see the implementation of closures in Python, the conditions for closures to exist, and the benefits of using closures.

What is a nested function in Python?

Nested functions in Python are the functions which are defined inside another function. Given below is an example of a nested function.

Here nested_function() is defined in the local scope of outer_function() and can only be called within the same scope unless it is returned by the outer_function during a function call.

#nested function example

def outer_function():
    x=10
    print("It is outer function which encloses a nested function")
    def nested_function():
        print("I am in nested function and I can access x from my enclosing function's scope. Printing x")
        print(x)
    nested_function()
#Execution
outer_function() 

Output:

It is outer function which encloses a nested function
I am in nested function and I can access x from my enclosing function's scope. Printing x
10

We can see that nested function can access a variable from it’s enclosing scope. When outer_function is called, it defines nested_function and in the end calls it which prints the value of x.

An important point to keep in mind is that functions are first class objects in python; i.e.functions can be passed as parameters, returned from other functions and assigned to any variable.

What is a free variable?

A variable can be accessed only within the scope where it has been defined i.e. if we declare a variable inside a function or a block then it can be used only inside that function or block. A name error will occur otherwise.

When a variable is used in a function or code block where it isn’t defined then the variable is called free variable.

x is a free variable in above example. Here nested_function can reference x because a function has access to the variables defined in the scope where it is defined.

What are closures in Python?

Closures in Python are used in object oriented programming by which a nested function remembers and has access to variables in the scope of the function in which it is defined.

Closures use nested functions and free variables in their implementation.

It is not necessary that the outer function should be alive when the nested function is executed i.e. the variables in the scope of the outer function may not be in the memory, still nested functions can have access to it.

In this way, data gets attached to code and isn’t even present in memory and then is used by nested functions.

What are the conditions for closures in Python to exist?

From the description above, we can easily identify that for closures in Python to exist.

  • We need to have nested functions.
  • Nested function needs to refer to variables defined in its outer scope i.e the outer function.
  • The third and most important condition for a closure to exist is that the outer function must return the nested function.

Example of Closures in Python

Let us see one example for closures in Python. Suppose we want to have a function which performs calculation on the number passed to it and prints the result.

#closure example
def generate_number():
    print("I am in generate_number function and will return the inner_function when called")
    x=999
    y=100
    def inner_function(number):
        result=(number*x)%y
        print("I am in inner function and printing the result")
        print(result)
    return inner_function

#execute
print("Calling generate_number")
do_something = generate_number()
print("Calling do_something")
do_something(77)

Output

Calling generate_number
I am in generate_number function and will return the inner_function when called
Calling do_something
I am in inner function and printing the result
23

In the above example,

  • The function generate_number() is defined which has two variables and a function inner_function defined in it’s scope.
  • The inner_function has access to variables x and y which are in the scope of the function generate_number. It performs the calculation and prints the result.
  • Now during execution, when we call generate_number() function, it completes it’s execution and returns inner_function to the variable do_something.
  • At this point, execution of generate_number gets over and it’s scope is cleared from the memory (See Python Garbage Collection).
  • Now the do_something variable starts acting as a function.
  • When we call this function, it executes inner_function and prints the result.

Here, the point to be noted is that inner_function is getting executed while generate_number has finished it’s execution.

Due to this, variables x and y are not in memory, still inner function has been able to use the variables.

This shows that the data has been attached to code instead of memory. This is the essence of closures.

Why should we use closures in Python?

Closures in Python can be used if we want to refrain from using global variables and thus can be used for data hiding. A very good usage of closures is done when decorators are implemented.

Conclusion

Alright, and that’s it for the day. We cover a lot of basic and advanced tutorials in Python for your needs. If you’re a beginner, try out this Python tutorial for beginners. Happy learning! 🙂