def fun(n, m):
    return n * m

Nested functions

def outer(a, b):
    c = "c"
    
    def inner():
        return a + b + c
        
    return inner()
    
print(outer("a", "b")) # abc

nonlocal keyword

We can modify obejcts but not reassign them in functions, unless we use the nonlocal keyword

def double(arr, val):
    def helper():
        # Modifying array works
        for i, n in enumerate(arr):
            arr[i] *= 2
        # val *= 2 does not work as it will only modify val in the helper's scope
        # instead:
        nonlocal val
        val *= 2
    helper()
    print(arr, val)
    
nums = [1, 2]
val = 3
 
double(nums, val) # [2, 4] 6