Python Closures


In this article, you will learn about Python closures, understand the logic behind closures, how to create closures and their significance in programming.

Nested function in Python
Non-local variables
Closures in Python: Introduction and Explanation
Why use closures?

python closures tutorial

Before diving into Python closures, there are few concepts one must be familiar with:

  • Nested functions
  • Non-local variables in Python.

So let’s learn about nested functions and non-local variables first.

Nested function in Python


A function defined inside another function is simply called a nested function.

Let’s take an example of nested function and illustrate the scope of non-local variables.

def function_outside():
   msg = 'Hello'
   def function_inside():
      print (msg)
   function_inside()

function_outside()

Output

Hello

Notice in above example, there is no local variable msg inside function_inside(), still, it prints the msg defined outside that function.

That is because when a function doesn’t find a local variable it looks up for a local variable defined inside the function it is enclosed or nested within. This is called the Enclosing scope.

Non-local variable in Python


Let’s consider following example to gain insight on non-local variable and its importance.

def function_outside():
  msg = 'Hi'
  def function_inside():
      msg = 'Hello'
      print (msg)
  function_inside()
  print (msg)

Now let’s try running this code in the interpreter.

>>> function_outside()
Hello
Hi

As you can see in above example when the function_outside() is called, first the function_inside() is invoked printing out the msg variable holding the value 'Hello'.

After that when we print msg again, it prints the value 'Hi'. That is because as soon as function_inside() terminates, the variable defined inside it is also destroyed. So the variable local to outer function is printed.

Now let’s see what happens when we use a non-local variable in function_inside( ).

def function_outside():
  msg = 'Hi'
  def function_inside():
      nonlocal msg
      msg = 'Hello'
      print (msg)
  function_inside()
  print (msg)

Now let’s try running this code in the interpreter.

>>> function_outside()
Hello
Hello

What just happened?

Well, when we declare a variable inside a nested function as nonlocal, its scope is extended beyond this inner-function to the outer-function it is nested within. Hence, the msg variable inside the inner function is bound to the msg variable in outer function overriding its value.

Now that we know about nested functions and non-local variables, let’s learn in depth about Python closures.

Python Closures: Introduction


Basically, the method of binding data to a function without actually passing them as parameters is called closure. It is a function object that remembers values in enclosing scopes even if they are not present in memory.

What do I mean by binding data to a function without actually passing them as parameters?

Let’s take an example to simplify it.

def func1():  #Outer function
  msg = 'I belong to func1'
  def func2(): #Nested function
      print (msg)
  return func2

 

In previous examples, we just called the nested function inside a function. Here we have returned the nested function instead of just calling it. This way we can return the whole functionality of nested function and bind it to a variable to use it further.

Let’s run this program in an interpreter and see what actually happens.

>>> obj = func1()  #binding the function to an object
>>> obj()
I belong to func1

Here is what’s happening in the program.

python closures example

But this is nothing new to what we saw in Nested functions, Where does closure come into play?

Well when the interpreter detects the dependency of inner nested function on the outer function, it stores or makes sure that the variables in which inner function depends on are available even if the outer function goes away.

python closure example

Technically the variable msg should have vanished away with outer function but s you can see in the picture, the variable msg in which the inner function depends on is bound to that function, even if the outer function goes away.

Hence, this method of binding data to a function without actually passing them as parameters is called closure. It is a function object obj that remembers values in enclosing scopes even if they are not present in memory.

Try the following code in an interpreter to see actual results.

>>> obj = func1()  #binding the function to an object
>>> del func1  #deleting the outer function
>>> func1()   #this returns error as the function is deleted
Traceback (most recent call last):
func1()
NameError: name 'func1' is not defined
>>> obj()
I belong to func1

As you can see in above example, even when the outer function is deleted the object still stores and binds the variable msg to inner nested function. This is called closure in Python.

In conclusion here are the three criteria’s for a closure:

  1. There must be a nested function (a function inside another function).
  2. This nested function has to refer to a variable defined inside the enclosing function.
  3. The enclosing function must return the nested function.

Why should we use closures?


  • Closures provide some sort of data hiding as they are used as callback functions. This helps us to reduce the use of global variables.
  • Useful for replacing hard-coded constants
  •  Closures prove to be efficient way when we have few functions in our code.