Python Closures?



In Python, you can define functions within functions i.e. nested. Python Closures are these inner functions enclosed within the outer function.

Understanding Inner and Outer Functions

Let us see a simple example to work around inner and outer functions −

Example

def outerFunc(a):
	# the enclosing function
	def innerFunc():
		# accessing outer function’s variable from inner function
		print(a)
	return innerFunc

# calling the enclosing function
demoFunc = outerFunc('Hello')
demoFunc()

Output

Hello

To understand Python Closures, lets first understand what’s nested function and python class.

Python Nested Function

A function defined inside another function is called a nested function. A nested function can access variables of the enclosing scope. Let us see an example −

Example

def funcOut():
	print("This is outer function.")
	def funcIn():
		print("This function is defined inside funcOut. \nThis function(funcIn) is called\ nested function.")
	print("We can call nested function here.")
	funcIn()
print("We are in outer function.\nCalling funcOut.")
funcOut()

Output

We are in outer function.
Calling funcOut.
This is outer function.
We can call nested function here.
This function is defined inside funcOut. 
This function(funcIn) is callednested function.

Therefore, the funcIn is the nested function which is defined inside funcOut. By seeing above output, we can understand the calling sequence of the functions. In case we want to have all the functionalities of funcIn from funcOut, for that we may have to do “return funcIn” in the above program, this is called closure in python. In short, a closure is a function (object) that remembers its creation environment (enclosing scope).

Example

def closureFunc(start):
	def incrementBy(inc):
		return start + inc
	return incrementBy
closure1 = closureFunc(9)
closure2 = closureFunc(90)
print ('clsure1(3) = %s' %(closure1(3)))
print ('closure2(3) = %s' %(closure2(3)))

Output

clsure1(3) = 12
closure2(3) = 93

Calling the variable closure1(which is of function type) with closure1(3) will return 12, while closure2(3) will return 93. While closure1 and closure2 are both referencing the same function incrementBy, we have two different variables closure1 & closure2 which are bind together by identifier closureFunc, leading to different results.

__closure__ attribute and cell objects

Use __closure__ attribute

To get more information we can use __closure__ attribute and cell objects −

Example

def closureFunc(start):
	def incrementBy(inc):
		return start + inc
	return incrementBy

a= closureFunc(9)
b = closureFunc(90)

print ('type(a)=%s' %(type(a)))
print ('a.__closure__=%s' %(a.__closure__))
print ('type(a.__closure__[0])=%s' %(type(a.__closure__[0])))
print ('a.__closure__[0].cell_contents=%s' %(a.__closure__[0].cell_contents))

print ('type(b)=%s' %(type(b)))
print ('b.__closure__=%s' %(b.__closure__))
print ('type(b.__closure__[0])=%s' %(type(b.__closure__[0])))
print ('b.__closure__[0].cell_contents=%s' %(b.__closure__[0].cell_contents))

Output

type(a)=<class 'function'>
a.__closure__=<cell at 0x7efdfb4683a8: int object at 0x7efdfc7324c0>
type(a.__closure__[0])=<class 'cell'>
a.__closure__[0].cell_contents=9
type(b)=<class 'function'>
b.__closure__=<cell at 0x7efdfb3f9888: int object at 0x7efdfc732ee0>
type(b.__closure__[0])=<class 'cell'>
b.__closure__[0].cell_contents=90

Advertisements