pythonfunctionnested-function

When to create a nested function inside a function and when to call it from outside?


I have seen some code that has these structures.

Structure 1: An internal function is created within a function

def external_func(num):
    def internal_func(num2):
        return num2*2
    return internal_func(num + 10)


test = external_func(5)
print(test)

Structure 2: A function is calling another function that is outside itself.

def _internal_func2(num2):
    return num2 * 2

def external_func2(num):
    return _internal_func2(num + 10)

test2 = external_func2(5)
print(test2)

For this particular case, both functions provide the same output. Where and why should I use each one of these structures?


Solution

  • One of the main benefits of Structure 1 is that it makes internal_func locally scoped to external_func. You are making it clear that internal_func should be accessed only by external_func. Treat it just like any other regular variable that was defined inside external_func. Similar to not having global variables scattered about, sometimes you want to "hide" an implementation inside other functions.

    You can then have other similarly named internal_func's in other methods and their names won't clash:

    In [39]: def external_func_x2(num):
        ...:     def f():
        ...:         return num * 2
        ...:     return f
        ...: 
    
    In [40]: def external_func_x3(num):
        ...:     def f():
        ...:         return num * 3
        ...:     return f
    

    One common purpose is to make functions that generate other functions based on certain conditions:

    In [44]: def make_multiplier(mult):
        ...:     def f(num):
        ...:         return num*mult
        ...:     return f
        ...: 
    
    In [45]: x4 = make_multiplier(4)
    
    In [46]: x4(8)
    Out[46]: 32
    
    In [47]: x3 = make_multiplier(3)
    
    In [48]: x3(8)
    Out[48]: 24
    

    You could do the same examples above with Structure 2 (or with functools.partial) but then it will be less readable, and you'll need to expose this inner f function in the outer scope/namespace, even though it's only used by the make_multiplier method. You'll also have to pass arguments around from one function to another, instead of having a closure like what we have with Structure 1.

    If you are making this make_multiplier as part of some library/API, using Structure 1 "hides" this f function and makes it a bit clearer and more readable to clients/users of the library/API that they only need to "see" the make_multiplier method.

    There is also an argument for maintainability. If you need to modify make_multiplier, it's already obvious that you need to modify f, and you can be pretty sure that modifying f will not break other parts of your code, since no one uses it other than make_multiplier.

    Structure 2 is your standard good practice of "splitting your big functions into smaller more manageable and reusable functions". Its main advantages over Structure 1 are testability and reusability. It is much easier to test and mock out _internal_func2 directly, without needing to call external_func2, which is great if external_func2 is especially complicated in itself to call. It would also be very difficult to write tests that directly target a nested inner function.

    It also makes _internal_func2 reusable by other methods. Comparing it to the example above for Structure 1, if you find yourself writing the same inner f nested inside many external_func's, then it's probably better to move that out and convert to Structure 2 style.