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:
outer()
function is created first but not called, so statements withinouter()
are not executed yet.function_call = outer()
is executed and functionouter()
is called. Now statements withinouter()
executes. Here is the execution flow for statements withinouter()
:- Variable message is created and value
"Welcome to Closures"
is stored. - Function
inner()
is created in the scope ofouter()
but not yet called. - Now,
return inner
is executed. So it returns:
to variable function_call. But within functiondef inner(): print("Message is: {0}".format(message))
inner()
, variable message is used which is Free Variable created inouter()
scope and used ininner()
.
- Variable message is created and value
- Finally
function_call()
is executed. In earlier step, function objectinner
is returned in variable function_call which meansfunction_call()
now actually calls functioninner()
.
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:
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:
- It has nested funcion. (A function within another function)
- Nested function refers to a variable defined in the enclosing scope. Or, lets say, there must be a free variables in inner function.
- 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