Closures in Python with Example & Characteristics

The technique by which free variables get attached to the function in Python is known as Closures. Python accomplish this task by creating an intermediary object called Cell.

In other words we can define closures as a function object that remembers some values. To understand how closures in Python remembers these values, let us consider following example:

Python Source Code: Closures Example


# Closure in Python

def outer():
    message = "Welcome to Closures"
    
    def inner():
        print("Message is: {0}".format(message))
    
    return inner


function_call = outer()

function_call() 

Output: Closures

The output of the above program is:

Message is: Welcome to Closures

Closures Explanation

So, how does above program works here? Here are the execution steps:

  1. outer() function is created first but not called, so statements within outer() are not executed yet.
  2. function_call = outer() is executed and function outer() is called. Now statements within outer() executes. Here is the execution flow for statements within outer():
    1. Variable message is created and value "Welcome to Closures" is stored.
    2. Function inner() is created in the scope of outer() but not yet called.
    3. Now, return inner is executed. So it returns:
      
      def inner():
              print("Message is: {0}".format(message))
      
      to variable function_call. But within function inner(), variable message is used which is Free Variable created in outer() scope and used in inner().
  3. Finally function_call() is executed. In earlier step, function object inner is returned in variable function_call which means function_call() now actually calls function inner().

So, question here is: how are we getting value of variable message on calling inner() in step 3 since variable message is defined in the scope of outer() but its scope is already destroyed, right? Quick answer: it is due to Closures.

Core Concept of Closure

Here we discuss the core concept behind Closures.

While creating function object inner(), Python sees that variable message is used within inner(), so it creates intermediary object called cell which points to str object "Welcome to Closures".

Now two references i.e. outer.message & inner.message are created and points to the intermediary object cell. Which is illustrated in following figures:

Understanding Closures & Creation of Cell
Figure: Understanding Closures & Creation of Cell

So, when scope of outer() is destroyed then it destroys outer.message but it does not destroy inner.message and is still available for inner() function. This is how Python attaches free variable message to inner() function & the concept is called Closures.

Characteristics of Closures

Python Closures has following characteristics:

  1. It has nested funcion. (A function within another function)
  2. Nested function refers to a variable defined in the enclosing scope. Or, lets say, there must be a free variables in inner function.
  3. It returns inner function from enclosing scope.

__closure__ Dunder

Additionally, you can view free variables and created cell during above-mentioned operation of Closures using dunder or magic methods __code__ and __closure__. Here is program & output:


# Closure in Python

def outer():
    message = "Welcome to Closure"
    
    def inner():
        print("Message is: {0}".format(message))
    
    return inner


function_call = outer()

function_call()  

print('Free variables: ', function_call.__code__.co_freevars)
print('Created cell information: ', function_call.__closure__)

Output

Message is: Welcome to Closure
Free variables:  ('message',)
Created cell information:  (<cell at 0x0000021DA5F4F5E8: str object at 0x0000021DA5F0CA80>,)

In the above python example, cell is created at 0x0000021DA5F4F5E8 and it is pointing to str object at 0x0000021DA5F0CA80 like we said earlier. Also read: Applications of Closures