python


Python Closure

Before learning about what a closure is, we have to first understand what are nested functions and non-local variables.
Nested functions in Python
A function which is defined inside another function will be a nested function. Nested functions can to access variables of the enclosing scope.
In Python, these non-local variables can be accessed only within their scopebut not outside their scope. This can be illustrated by following example:


# Python program to illustrate 
# nested functions 
def outerFunction(text): 
    text = text 
  
    def innerFunction(): 
        print(text) 
  
    innerFunction() 
  
if __name__ == '__main__': 
    outerFunction('Hey!')
As we can see here innerFunction() can easily be accessed inside the outerFunction body but not outside of it’s body. Hence, here, innerFunction() is treated as a nested Function which uses text as it's non-local variable.
A Closure is a function object that remembers values in enclosing scopes even if they are not available in memory.
It is a record which stores a function together with an environment: a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bounded when the closure creation took place. A closure,unlike a plain function—allows the given function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.

# Python program to illustrate 
# closures 
def outerFunction(text): 
    text = text 
  
    def innerFunction(): 
        print(text) 
  
    return innerFunction # Note we are returning function WITHOUT parenthesis 
  
if __name__ == '__main__': 
    myFunction = outerFunction('Hey!') 
    myFunction() 

Output:

Hey!
As observed from the code given above, closures help to invoke function outside their scope.
The function named innerFunction has its scope only inside the outerFunction. But with the use of closures we can easily extend it's scope to invoke a function outside of it's scope.

# Python program to illustrate 
# closures 
import logging 
logging.basicConfig(filename='example.log', level=logging.INFO) 
  
  
def logger(func): 
    def log_func(*args): 
        logging.info( 
            'Running "{}" with arguments {}'.format(func.__name__, args)) 
        print(func(*args)) 
    # Necessary for closure to work (will return WITHOUT parenthesis) 
    return log_func               
  
def add(x, y): 
    return x+y 
  
def sub(x, y): 
    return x-y 
  
add_logger = logger(add) 
sub_logger = logger(sub) 
  
add_logger(3, 4) 
add_logger(4, 5) 
  
sub_logger(10, 4) 
sub_logger(20, 10) 
Output
 
7
9
6
10
When and why to use Closures:
As closures are used as callback functions, they will provide some sort of data hiding. This helps us to reduce the use of global variables.
When we have few functions in our code, closures proved as efficient way. But if we need to have many functions, then go for class (OOP).