A function is a block of code that can be called again and again in a program. It can accept different arguments and can return some useful value. In all programming languages, we have built-in functions and user-defined functions.
In this tutorial, we will learn how to create and use nested functions in Python.
Most of the languages support the use and creation of nested functions. As the name suggests, a nested function is a function within a function. The function nested inside is called the inner function, and the enclosing function is called the outer function.
In the following code, we create a basic nested function.
def outer_f(s): def inner_f(s): print(s) inner_f(s) outer_f("Nested")
Using the above example, we can get a little idea about the use of nested functions. They can be used to hide a function from the outside world and implement data encapsulation.
Another thing to know is that the nested function can use the variable used in the outer function. Such variables are called non-local. Nested functions can access them, but if we need to modify them, we have to use the
Let’s see the following example.
def outer_f(): s = 5 def inner_f(): nonlocal s s = s+1 return s return inner_f() print(outer_f())
Here we would not be able to modify the
s variable without using the
Now imagine if the nested function returns some value. This brings us to another useful feature of nested functions and which is closure functions. These functions are dynamically created using nested functions. It may be an elegant and concise way to implement data hiding and use it as an alternative for classes.
See the following code.
def incrementer(x): def inc(y): return x + y return inc by4 = incrementer(4) by5 = incrementer(5) print(by4(5), by5(5))
Now in the above code, we create a dynamic method to increment a number. The
by5 are the two closure functions created using the nested function. This is mainly due to the ability of the nested functions to retain their state. It can be a decent alternative to classes and global variables when not too many attributes are involved. We can find out if a function is a closure using the
__closure__ attribute. All functions have this attribute ad it returns some cell objects when used with a closure function.
The nested functions are also used for decorator functions. Decorator functions use a callable object like a class, function, and return another object. We use the
@ sign to use a decorator before any such callable object. This way, we take the callable object as an argument of the decorator function and use it.
We create a very simple decorator function to understand this better in the following example.
def dec(func): def inner(): print("Hello") func() return inner @dec def world(): print("world") world()
In the above example, we created a simple decorator function called
dec(), which decorates the
world() function by using it as an argument and printing an additional message.