Close
Close

Python Nested Functions


We can do a lot with functions like passing a function as an argument to another function, calling a function from another function, etc. In Python, we can also create a function inside another function. 

A function which is created inside another function is called a nested function or an inner function. In this chapter, we will read about nested functions and their significance.

Defining a Nested Function


A nested function is defined by simply creating it using the def keyword inside another function. 

Here is an example.

def outer():  # outer function
    print("This is outer function")
	
    def inner():
        print("This is inner function")
	
    inner()  # calling inner function
 
outer()  # calling outer function
Output
This is outer function
This is inner function

We defined a function named inner() inside another function named outer(). Thus, inner() is a nested function. 

When the outer() function is called, its body is executed. Inside its body, the inner() function is defined and then called. Thus, we first called the outer() function which in turn called the inner() function.

Note that an inner function is always called from inside the function in which it is defined. Thus, to call the inner function, we need to call the outer function.

A nested function can access the variables defined in the function in which it is created. This is demonstrated in the following example.

def outer():  # outer function
    x = 10

    def inner():
        print("Inside inner func", x)

    inner()  # calling inner function
    print("Inside outer func", x)
 
outer()  # calling outer function
Output
Inside inner func 10
Inside outer func 10

In this example, we defined a variable x having a value of 10 in the outer() function. When we printed the value of x in the nested function, it got printed. This means that the nested function can access the variable x defined in its parent function.

So, from the above examples you must have understood that nested functions are just normal functions which are defined and called inside some other function.

Let’s see one more example.

def find_power(num):  # outer function

    def power(n):
        return num ** n

    return power(2)  # calling inner function and returning the value returned by it

print(find_power(10))  # calling outer function
Output
100

This was a straight forward example. The find_power() function is called by passing 10 as argument, making its parameter num equal to 10. Inside the find_power() function, the nested function power() is called by passing 2 as argument, making the parameter n of the power() function equal to 2. Inside the power() function, num (10) raised to the power n (2) is returned. Finally, this value returned by the power() function is returned by the find_power() function.

Significance of Nested Functions


There can be many reasons to use nested functions. Let’s see some of them.

Nested functions can serve as helper functions of the function in which they are defined. Let’s see an example in which a nested function serves as a helper function for its parent function.

def print_even(lst):

    def find_even(num):
        if num % 2 == 0:
            return True
        else:
            return False

    new_list = []

    for num in lst:
        if find_even(num) == True:
            new_list.append(num)
	
    print("Final list:", new_list)
 
mylist = [1, 2, 4, 5, 6, 7, 10, 11, 12]
print_even(mylist)
Output
Final list: [2, 4, 6, 10, 12]

Here the function print_even() receives a list as the argument and prints a new list containing all the even elements of the list received. You must have understood the rest of the program.

Inside the print_even() function, we have a nested function find_even() which receives a number as the argument and returns True if the passed number is even, else returns False. In this program, the nested function thus works as a helper function which just checks if the passed number is even and is not affected by any other code or variable inside the outer print_even() function.

Another use case of nested functions can be seen from the following example.

def get_factorial(num):

    def factorial(num):
        if num == 0 or num == 1:
            return 1
        else:
            return num * factorial(num - 1)

    if not isinstance(num, int):
        raise TypeError("Failed! The value must be a number")

    if num < 0:
        raise ValueError("Failed! The number must be non-negative")
	
    return factorial(num)

print(get_factorial(5))
Output
120

In the above example, the get_factorial() function takes a number as argument and returns the factorial of that number. Inside the get_factorial() function, we are doing some error handling, in which we are raising the TypeError exception if the passed number is not an integer and the ValueError exception is the passed number is less than 0 (You can learn about raising exceptions from this chapter). If no exception is thrown in both the checks, then the nested function named factorial() is called which returns the factorial of the number. 

Now suppose if the code for both error handling and factorial calculation was written in the get_factorial() function without using the nested function factorial(), the complexity of the code inside get_factorial() would have increased.

So by now, you must have got an idea of when you can use nested functions to reduce the complexity of your functions. Let’s look at some more cases when nested functions can be used.

Sometimes we might want to prevent some function from being directly accessed from anywhere in your program. In that case, we can put that function (say f2()) as a nested function inside another function (say f1()). We know that a nested function can’t be accessed outside the function in which it is defined, and hence we won’t be able to access that function from other parts of the program anymore. In order to call the nested function f2(), we first will have to call its parent function f1() which will call f2() inside it. This hiding of some data or code (function in our case) is known as encapsulation.

But why would we encapsulate a function?

To answer that, let’s take a use case where we want to predict if a company will get profit or loss. Suppose we have a function which contains a logic that calculates the expected profit of a company. This logic might contain some information which we don’t want anyone to know. If we don’t want any other part of the program to directly access the logic in this function, we can put it as a nested function inside another function. Look at the following function structure.

def profit_or_loss():

    def get_profit():
        # calculates profit
        return profit

    if profit > 0:
        return "Profit"
    else:
        return "Loss"

profit_or_loss()

Suppose get_profit() is the nested function with the logic that calculates and returns the expected profit, and profit_or_loss() is the function inside which it is encapsulated. Now, if the user wants to know if there will be profit or loss, then he/she will call the profit_or_loss() function. This function will call the get_profit() function to get the profit, and will return “Success” if the profit is positive, else returns “Loss”. In this way, no other part of the program is able to access the nested get_profit() function.

Nested functions are also used for creating closures. We will read about closures in Closures.

Now that you understand what nested functions are and where to use them, start including them in your programs wherever necessary.

To learn from simple videos, you can always look at our Python video course on CodesDope Pro. It has over 500 practice questions and over 20 projects.
Life is 10% what happens to us and 90% how we react to it.
- Dennis P. Kimbro


Ask Yours
Post Yours
Doubt? Ask question