Python Closures?

PythonServer Side ProgrammingProgramming

To better understand python closures, lets first understand what’s nested function and python class. In short, python closure is also a function which encapsulates data with code.

Python nested function

A function defined inside another function is called a nested function. A nested function can access variables of the enclosing scope.

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 called nested function.

So, 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).

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

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

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 0x057F8490: int object at 0x68A65770>

type(a.__closure__[0]) = <class 'cell'>
a.__closure__[0].cell_contents = 9

type(b)=<class 'function'>
b.__closure__ = <cell at 0x0580BD50: int object at 0x68A65C80>

type(b.__closure__[0]) = <class 'cell'>
b.__closure__[0].cell_contents=90

From the above output, we can see each cell of the objects retains the value at the time of its creation.

raja
Published on 08-Apr-2019 12:21:28
Advertisements