Nested function, Scope of variable & closures in Python

Nov. 7, 2017 29793

This post first introduces nested functions and then the different scopes of variables like global variables, local variables in functions etc., and finally, closures using the nested function in Python.

You can learn about Python's function from our Python course and this post.

Nested function

Like nested loops, we can also have nested functions in Python. We simply create a function using def inside another function to nest two functions. For example,

def f1(): #outer function
print ("Hello")
def f2(): #inner function
print ("world")
f2()

f1()


Output

Hello world

def f1(): #outer function
x = 1 #variable defined in f1 function
def f2(a): #inner function
print (a+x) #able to acces the variable of outer function
f2(2)

f1()


Output

3

This seems quite simple. You can see that we also accessed the variables of the outer function from the inner function. So, let's try to change the variables of the outer function from the inner one.

def f1(): #outer function
x = 1 # variable defined in the outer function
def f2(a): #inner function
#will create a new variable in the inner function
#instead of changing the value of x of outer function
x = 4
print (a+x)
print (x) # prints the value of x of outer function
f2(2)

f1()


Output

1 6

From the above two examples, you can see that we are able to print the variables of the outer function from the inner one but not able to change it. x=4 created a new variable named 'x' inside the function f2 instead of changing the value of the variable 'x' of the function f1. So before moving on to more discussions about nested functions, let's know about the scope of variables in Python first, i.e., where variables live and from where we can access them.

Scope of variables

The location where we can find a variable and also access it if required is called the scope of a variable. So, let's learn what these scopes are.

Local and Global variables

A variable in a function in Python is a local variable if it is not declared as something else. A local variable can be accessed only locally i.e., a variable defined inside a function is accessible to that function only and can't be used outside the function.

def f1():
a = 5
f1()
#a can't be accessed outside the function f1
print (a) # will give error


Output
Traceback (most recent call last):   File "a.py", line 5, in <module>     print x # will give error
NameError: name 'x' is not defined

You can see that the variable 'a' created inside the function is a local variable and is inaccessible outside the function.

Also, we can access from a function the variables which are defined outside that function but can't modify them.

a = 5
def f1():
print (a) # will print 5

f1()


Output
5

We are able to print the global variable 'a'. Python first looked for a variable named 'a' inside the function and when it was not found, it looked in the global scope and printed the global value of 'a'.

a = 1
def f1():
a = 5
print (a) #will print 5

print (a) #will print 1

f1()


Output

1 5

You can see that declaring a = 5, created a new local variable inside the function instead of changing the existing global variable 'a'. This is because Python assumes that a variable is local if it is not explicitly declared global.

To tell Python that we want to use the global variable inside the function, we need to use the global keyword. An example is given below.

a = 1
def f1():
global a #using global variable a
a = 5 #global variable is changed to 5
print (a) #will print 5

f1()
print (a) #will print 5


Output
5 5

Please note that unlike other languages like C, Python doesn't have any separate scope for loops, if/else, etc. Thus, changing variables inside a loop will change the global variable also.

a = 1
if True:
a = 2
print (a)


Output
2

a = 1
for i in range(1,10):
a = i
print (a)


Output
9

After understanding global and local variables, let's dive into the scope of variables in nested functions.

Scope of variables in nested function

We already know how to access a global variable form a function.
In this section, we will learn about accessing and changing the variables of an outer function from the inner one. So, first let's try to print a variable of an outer function from the inner one.

def f1(): #outer function
a = 1
def f2(): #inner function
print (a) #will print 1
f2()
f1()


Output
1

You can see that we are able to print the variable of the outer function. This is similar to printing a global variable from a function.

Let's try to change the value of the variable of an outer function.

def f1(): #outer function
a = 1
def f2(): #outer function
a = 2
print (a) #prints 2
f2()
print (a) #prints 1
f1()


Output
2 1

You can see that we are not able to change the value of the variable of the outer function from the inner one. a=2 created a new local variable of function f2 instead of changing the value of 'a' from the function f1.

There are different ways to change the value of the local variable of the outer function from the inner function. The first way is to use an iterable.

def f1(): #outer function
a = [1]
def f2(): #outer function
a[0] = 2
print (a[0]) #prints 2
f2()
print (a[0]) #prints 2
f1()


Output
2 2

We can also change the value of the variable as shown in the next example.

def f1(): #outer function
f1.a = 1
def f2(): #outer function
f1.a = 2
print (f1.a) #prints 2
f2()
print (f1.a) #prints 2
f1()


Output
2 2

The third way is to use the nonlocal keyword. Please note that the nonlocal keyword only works with Python3. You can use any of the two ways mentioned above to change the value of the variable in Python2.

We can use the nonlocal keyword to change the value of the variable of the outer function similar to using global keyword to change the value of global variables.

def f1(): #outer function
a = 1
def f2(): #outer function
nonlocal a
a = 2
print (a) #prints 2
f2()
print (a) #prints 2
f1()


Output
2 2

As you are ready with the concepts of scopes of variables, let's learn about closures in Python.

Closure

Closure is basically keeping a record of a function with an environment. For example, if we call a function with an argument (foo(1)), then it must keep a record of the environment with that argument to be used later in the program. It will be clear from the examples given below.

def f1(a):
def f2(b):
return a+b
return f2
a = f1(1)
b = f1(100)

print (a(2))
print (b(2))


Output
3 102

You can see that the environment created by f1(1) is different from that of f1(100), and both were remembered by Python, thus printing different values for a(2) and b(2). This is what closure is.

So basically, a function (object) that remembers the environment where it was made is a closure.

A closure is also the answer to the question - "What is the use of nested function". But this also gives us another question - "What is the use of closures?"

Classes are more flexible than closures but closures are faster. One can make closures to handle simple cases where making a class is not really necessary.

Liked the post?
Developer and founder of CodesDope.
Editor's Picks
0 COMMENT