*This notebook contains an excerpt from the Python Programming and Numerical Methods - A Guide for Engineers and Scientists, the content is also available at Berkeley Python Numerical Methods.*

*The copyright of the book belongs to Elsevier. We also have this interactive book online for a better learning experience. The code is released under the MIT license. If you find this content useful, please consider supporting the work on Elsevier or Amazon!*

< 3.2 Local Variables and Global Variables | Contents | 3.4 Lambda Functions >

# Nested functions¶

Once you have created and saved a new function, it behaves just like any other Python built-in function. You can call the function from anywhere in the notebook, and any other function can call on the function as well. A **nested function** is a function that is defined within another function - **parent function**. Only the parent function is able to call the nested function. However, the nested function retains a separate memory block from its parent function.

**TRY IT!** Consider the following function and nested function.

```
import numpy as np
def my_dist_xyz(x, y, z):
"""
x, y, z are 2D coordinates contained in a tuple
output:
d - list, where
d[0] is the distance between x and y
d[1] is the distance between x and z
d[2] is the distance between y and z
"""
def my_dist(x, y):
"""
subfunction for my_dist_xyz
Output is the distance between x and y,
computed using the distance formula
"""
out = np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)
return out
d0 = my_dist(x, y)
d1 = my_dist(x, z)
d2 = my_dist(y, z)
return [d0, d1, d2]
```

Notice that the variables *x* and *y* appear in both *my_dist_xyz* and *my_dist*. This is permissible because a nested function has a separate memory block from its parent function. Nested functions are useful when a task must be performed many times within the function but not outside the function. In this way, nested functions help the parent function perform its task while hiding in the parent function.

**TRY IT!** Call the function *my_dist_xyz* for x = (0, 0), y = (0, 1), z = (1, 1). Try to call the nested function *my_dist* in the following cell.

```
d = my_dist_xyz((0, 0), (0, 1), (1, 1))
print(d)
d = my_dist((0, 0), (0, 1))
```

```
[1.0, 1.4142135623730951, 1.0]
```

```
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-2-1bec838581d7> in <module>
1 d = my_dist_xyz((0, 0), (0, 1), (1, 1))
2 print(d)
----> 3 d = my_dist((0, 0), (0, 1))
NameError: name 'my_dist' is not defined
```

Following is the code repeated without using nested function. Notice how much busier and cluttered the function looks and how much more difficult it is to understand what is going on. Also note that this version is much more prone to mistakes because you have three chances to mistype the distance formula. It is worth noting that this function could be written more compactly using vector operations. We leave this as an exercise.

```
import numpy as np
def my_dist_xyz(x, y, z):
"""
x, y, z are 2D coordinates contained in a tuple
output:
d - list, where
d[0] is the distance between x and y
d[1] is the distance between x and z
d[2] is the distance between y and z
"""
d0 = np.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)
d1 = np.sqrt((x[0]-z[0])**2+(x[1]-z[1])**2)
d2 = np.sqrt((y[0]-z[0])**2+(y[1]-z[1])**2)
return [d0, d1, d2]
```

< 3.2 Local Variables and Global Variables | Contents | 3.4 Lambda Functions >