Python Closures
To understand the concept of closures in python we must know what are nested functions and non-loc al variables. So let's start with them first.
Nested functions and Non-local variables
When a function is defined inside another function then this is called nesting of functions, where, the function inside which another function is defined is called the outer function and the function which is defined inside another function is called the inner function. An example depicting the use of nested functions is shown below:
#defining nested function
def outer(message):
#text is having the scope of outer function
text = message
def inner():
#using non-local variable text
print(text)
#calling inner function
inner()
# main method
if __name__=='__main__':
outer('Hello!')
Hello!
In the above code snippet, the inner function inner()
is able to access the local variable text
of the outer function outer()
which has a scope that extends up to the whole body of the outer()
function. The local variable text
of the outer function is a non-local variable for the inner function which it can access but not modify.
Understanding the concept of Closures
A closure is a function object (a function that behaves like an object) that remembers values in enclosing scopes even if they are not present in memory.
When a function is available inside another function then closure is created. The inner function will have access to variables and parameters of outer function even after outer function is returned. This means that we can call the inner function later and it will have access to variables and parameters of outer function. Actually, the closure has reference to the variables and parameters of outer function. We can say that, closure is a record that stores a function together with an environment.
#defining nested function
def outer(message):
#text is having the scope of outer function
text = message
def inner():
#using non-local variable text
print(text)
#return inner function
return inner
# main method
if __name__=='__main__':
func = outer('Hello!')
func()
Hello!
In the above example, we have used a closure to access inner()
function out of its scope, as the inner()
function is only available inside the outer()
function but by returning it, we can access it outside the outer()
function.
Then in the main method, we have called the outer()
function and returned the inner()
function reference to the func
variable.
Now, the func
variable has reference to the inner()
function which means when we use parentheses with the func
variable then it works as inner()
function which is accessing the text
variable of outer()
function that was called at the time of the declaration of func
variable.
Let's take one more example:
This example is a little more complex, as here we have used arguments in the inner operation(n)
function. So, when the inrementor(m)
function is called, it returns the reference to operation(n)
function.
And while defining the variables incrementby1
, incrementby5
and incrementby9
, we have passed the value of m
argument every time.
Hence, the variables incrementby1
, incrementby5
and incrementby9
refer to the operation(n)
function with the value of m
argument set as 1, 5 and 9 respectively.
And then while calling the operation(n)
function using the variables incrementby1
, incrementby5
and incrementby9
, we have also passed the value of n
and hence got the desired outputs.
Important Points to Remember about Closures
Following are some useful points which also form necessary conditions for implementing closures in python:
- There should be nested function i.e. function inside a function.
- The inner function must refer to a non-local variable or the local variable of the outer function.
- The outer function must return the inner function.
When to use Closures?
Following are some use cases when closures should be used in python.
- Closures can avoid the use of global values.
- It provides some form of data hiding.
- When there are few methods (one method in most cases) to be implemented in a class, closures can provide a better solution. But when the number of attributes and methods are more, it is better to implement a class.