Python Closure

Overview

Before I talk about what Closure is and what it does? Let’s first understand scope resolution and nested function.

Scope

Whenever a python interpreter looks for the scope of a variable or function, it first searches in the Local namespace. If no match is found, it will look for it in the Enclosing scope, then Global scope and if still there is no match, it checks for it in the Built-in scope before raising the NameError exception.

Nested Function 

A function inside another function is known as a nested function. Nested functions can only be accessed inside Outer functions. These nested functions can access variables defined inside an outer function. This property of being able to access variables leads to the concept of closure.

Code:

Python Code

def Outer(var):
	def Inner():
		print(var)
	Inner()
Outer('message')

Output: message

Python Closure

Since almost everything in Python is an object, therefore we can say that closure is an inner function object. More specifically, closure is a function object capable of remembering the environment in which it was created. This helps closure to access variables even after the outer function has finished its execution or even if we explicitly delete the Outer function. It also helps in extending the scope of the inner function. We can say that closure is a function that has variables bound to it immutably(data cannot be changed using closure). While returning the inner function, unlike the nested function we don’t use (Parenthesis) in closure.

Code:

Python Code

def Outer(inp):
	def Inner():
		print(inp)
	return Inner

output = Outer('Calling inner function')
print(output.__closure__[0].cell_contents)
output.__closure__[0] = 'Calling outer function'

Output:

Calling inner function

TypeError: ‘tuple’ object does not support item assignment

Now if we explicitly delete the Outer function. We will still be able to access the inner function.

Code:

Python Code

def Outer(inp):
	def Inner():
		print(inp)
	return Inner
a = Outer('Calling inner function')
del Outer
print(Outer('Can we access Outer after deleting'))
a()

Output:

NameError: name ‘Outer’ is not defined

Since we have deleted the Outer function, now if we try to access the inner function we can access it as closure remembers the environment in which it was created.

Code:

Python Code

def Outer(inp):
	def Inner():
		print(inp)
	return Inner
a = Outer('Calling inner function')
del Outer
a()

Output: Calling inner function

Closure with parameter

We can also pass parameters inside an inner function using a closure.

Code:

Python Code

def multiplyFirst(x):
	def multiplySecond(y):
		return x*y
	return multiplySecond

multi = multiplyFirst(5)
print(multi(5))

Output: 25

Criteria for Closure

  1. There must be a nested function.
  2. The nested function refers to the value defined in the enclosing function.
  3. The outer Function must return the inner function.

When to use Closure

  1. Closure can be used as a replacement for a class. Consider when you have only one method inside a class. You can use closure to avoid unnecessary instantiation of objects and instance variables. It also helps in improving the readability of code. 
  2. Closure can be used with a decorator.
  3. The closure is also helpful in reducing the unnecessary usage of global variables.
  4. Closures are somewhat like a callback function; you cannot access them directly. It helps in data hiding. Suppose your outer function serves the functionality of the submit button, you can implement some functionalities inside the closure which will basically make sure what should happen after some click on the submit button. 

Special thanks to Arya Singh for contributing to this article on takeUforward. If you also wish to share your knowledge with the takeUforward fam, please check out this articleIf you want to suggest any improvement/correction in this article please mail us at [email protected]