Can i call inner function python?

Hello Learners, today we will learn how to call a nested function in Python with this small tutorial.

Just like nested loops or conditions, nested functions are nothing but function within a function i.e. a function defined inside another function.

Python supports First-Class Function which means python treats the functions as objects. You can pass functions as an argument, return them or you can save them in data structures also. You can do it using Python Closures i.e. a function instance enclosed within an enclosing scope.

There is one thing you should take care of, you must have to call the outer function to call the inner function because it’s scope is inside that function.

So without wasting the time let’s jump into the code snippet so you can have a better understanding of the concept.

def func[x]:
    print['hello']
    print["{} is of type {}".format[x,[type[x]]]]
    
    def nested[x]:
        print['inside nested function']
        x=int[x]
        print["{} is of type {}".format[x,[type[x]]]]
    nested[x]
  
func['2']

OUTPUT:

hello
2 is of type 
inside nested function 
2 is of type 

In this code snippet, on calling function func[] with value 2 of string type, it starts executing.

On line 9 it calls the nested function within the func[] function and then the nested function is executed.

So in this manner, the nested function is called every time we call the func[] function automatically because it is called inside the func[] function.

The Requirement of Nested Functions: nested function call

Python Closures or you can say nested function objects can be used to protect or filter some functionalities inside that function. These functionalities are protected from outer space or processes which is nothing but Encapsulation. It can be achieved by using nested functions.

Now suppose you don’t want to execute the nested[] function all the times you call func[], what will you do now?

def func[x]:
    print['hello']
    print["{} is of type {}".format[x,[type[x]]]]
    
    def nested[x]:
        x=int[x]
        print["inner function : {} is of type {}".format[x,[type[x]]]]
    
    print["{} is of type {}".format[x,[type[x]]]]
    return nested

f = func['2']
f['2']

OUTPUT: 

hello
2 is of type 
2 is of type 
inner function : 2 is of type 

In this code snippet, the outer function is called on line 12 but the inner function is not. It will be called only when we call this new function named ‘f’  with specified arguments.

On line 13, we called f with the parameter required and we can see the output. The inner function is called and the argument is converted into an integer.

There is another concept of nonlocal keyword which we’ll learn in another tutorial when we’ll discuss the scope of variables. For now, you can see this article for the nonlocal keyword.

Nonlocal variable in a nested function

Before getting into what a closure is, we have to first understand what a nested function and nonlocal variable is.

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

In Python, these non-local variables are read-only by default and we must declare them explicitly as non-local [using nonlocal keyword] in order to modify them.

Following is an example of a nested function accessing a non-local variable.

def print_msg[msg]:
    # This is the outer enclosing function

    def printer[]:
        # This is the nested function
        print[msg]

    printer[]

# We execute the function
# Output: Hello
print_msg["Hello"]

Output

Hello

We can see that the nested printer[] function was able to access the non-local msg variable of the enclosing function.

Defining a Closure Function

In the example above, what would happen if the last line of the function print_msg[] returned the printer[] function instead of calling it? This means the function was defined as follows:

def print_msg[msg]:
    # This is the outer enclosing function

    def printer[]:
        # This is the nested function
        print[msg]

    return printer  # returns the nested function


# Now let's try calling this function.
# Output: Hello
another = print_msg["Hello"]
another[]

Output

Hello

That's unusual.

The print_msg[] function was called with the string "Hello" and the returned function was bound to the name another. On calling another[], the message was still remembered although we had already finished executing the print_msg[] function.

This technique by which some data ["Hello in this case] gets attached to the code is called closure in Python.

This value in the enclosing scope is remembered even when the variable goes out of scope or the function itself is removed from the current namespace.

Try running the following in the Python shell to see the output.

>>> del print_msg
>>> another[]
Hello
>>> print_msg["Hello"]
Traceback [most recent call last]:
...
NameError: name 'print_msg' is not defined

Here, the returned function still works even when the original function was deleted.

When do we have closures?

As seen from the above example, we have a closure in Python when a nested function references a value in its enclosing scope.

The criteria that must be met to create closure in Python are summarized in the following points.

  • We must have a nested function [function inside a function].
  • The nested function must refer to a value defined in the enclosing function.
  • The enclosing function must return the nested function.

When to use closures?

So what are closures good for?

Closures can avoid the use of global values and provides some form of data hiding. It can also provide an object oriented solution to the problem.

When there are few methods [one method in most cases] to be implemented in a class, closures can provide an alternate and more elegant solution. But when the number of attributes and methods get larger, it's better to implement a class.

Here is a simple example where a closure might be more preferable than defining a class and making objects. But the preference is all yours.

def make_multiplier_of[n]:
    def multiplier[x]:
        return x * n
    return multiplier


# Multiplier of 3
times3 = make_multiplier_of[3]

# Multiplier of 5
times5 = make_multiplier_of[5]

# Output: 27
print[times3[9]]

# Output: 15
print[times5[3]]

# Output: 30
print[times5[times3[2]]]

Output

27
15
30

Python Decorators make an extensive use of closures as well.

On a concluding note, it is good to point out that the values that get enclosed in the closure function can be found out.

All function objects have a __closure__ attribute that returns a tuple of cell objects if it is a closure function. Referring to the example above, we know times3 and times5 are closure functions.

>>> make_multiplier_of.__closure__
>>> times3.__closure__
[,]

The cell object has the attribute cell_contents which stores the closed value.

>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5

Can you access inner function Python?

In Python, inner functions have direct access to the variables and names that you define in the enclosing function. This provides a mechanism for you to create helper functions, closures, and decorators.

Can you call a function inside a function Python?

In Python, any written function can be called by another function. Note that this could be the most elegant way of breaking a problem into chunks of small problems.

How do you call an inner function?

Approach:.
Write one function inside another function..
Make a call to the inner function in the return statement of the outer function..
Call it fun[a][b] where a is parameter to outer and b is to the inner function..
Finally return the combined output from the nested function..

Can you call functions inside of functions?

Calling a function from within itself is called recursion and the simple answer is, yes.

Bài mới nhất

Chủ Đề