In this section, we will learn what inner functions are and how to use them in Python.
Note: we are also assuming you’re familiar with functions in python.
What is Inner Functions in Python?
Within the body of a function, we can declare any object, and that includes another function as well!
A function that is declared within the body of another function is called inner function.
Note: we can return an inner function as the result of calling a function. Pass that inner function as the argument to another function, etc. All of this possible because of the fact that functions are just objects like any other objects we have in Python. Basically, the name of a function is nothing but a pointer to a memory location where the actual function resides.
So when we return a function from another function, what we do is basically returning a pointer to the target function. Now this pointer could be assigned to another variable or passed to a parameter of another function etc. and all of them will point to the same function.
Declaring Inner Functions in Python
There’s no different between the way we declare a function within the body of another function from the way a typical function is created. Simply put, the def keyword, the name of the function and a pair of parentheses with any necessary parameters and then define the body of that function.
Example: using inner functions in Python
glob = 100 def funcOne(): glob = 200 def innerFunc(): print(glob) return innerFunc res = funcOne() res()
Output:
200
How Does Inner Functions Work in Python?
In the last example, we have a function called `funcOne` and inside its body there’s another function called `innerFunc`. Within the body of the `funcOne` we returned the `innerFunc` as the final return value of this function. This means now the `res` variable is pointing to the same function as the `innerFunc` identifier does.
So we can use the `res` variable to call that innerFunc as well.
Now the important part that you should be aware of is that inner functions remember their scopes! This means if we call a function and in that function there was a call to a variable, here’s what will happen:
1- The execution engine first will check its local scope and inner body to see if there’s a variable with the mentioned name. If yes, it will take its value and use it in the operation.
2- If the target function didn’t have the value, the execution engine will check its enclosing scope to see if that scope has such a variable. If yes, then it will take its value. (For an inner function, the enclosing scope is the scope of the parent function where the inner function is defined in).
3- The execution engine search its way up to the global scope for the target variable and finally if the global scope didn’t have the target variable, then an error will return as a result.
So here, when we called the `res()` function, the execution engine first opened the body of the `innerFunc` to execute its body.
Within the body of the `innerFunc` there’s a call to a variable named `glob`. So the engine first checks the body of the `innerFunc` to see if there’s a variable with this name. But, there isn’t!
So the engine will move one step above and checks the enclosing scope which is `funcOne` function. Here there’s a variable with the name `glob`. So the engine will take the value of that variable and use it in the body of the `innerFunc` where the value is needed (in the print() function).
That’s how we got the value 200 on the output stream.
Be aware that if the `funcOne` didn’t have the `glob` variable then the engine would’ve moved one step further and checked the final scope which is the global scope for this example to see if there’s a variable with the name `glob` or not. Now, because there’s one, it would use the value of that variable in the body of the `innerFunc` function.
Note: we will return to this concept in the closure section as well.