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?
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.