Is nested function a good approach when required by only one function? [closed]
You don't really gain much by doing this, in fact it slows
method_a down because it'll define and recompile the other function every time it's called. Given that, it would probably be better to just prefix the function name with underscore to indicate it's a private method -- i.e.
I suppose you might want to do this if the nested function's definition varied each time for some reason, but that may indicate a flaw in your design. That said, there is a valid reason to do this to allow the nested function to use arguments that were passed to the outer function but not explicitly passed on to them, which sometimes occurs when writing function decorators, for example. It's what is being shown in the accepted answer although a decorator is not being defined or used.
Here's proof that nesting them is slower (using Python 3.6.1), although admittedly not by much in this trivial case:
setup = """class Test(object): def separate(self, arg): some_data = self._method_b(arg) def _method_b(self, arg): return arg+1 def nested(self, arg): def method_b2(self, arg): return arg+1 some_data = method_b2(self, arg)obj = Test()"""from timeit import Timerprint(min(Timer(stmt='obj.separate(42)', setup=setup).repeat())) # -> 0.24479823284461724print(min(Timer(stmt='obj.nested(42)', setup=setup).repeat())) # -> 0.26553459700452575
Note I added some
self arguments to your sample functions to make them more like real methods (although
method_b2 still isn't technically a method of the
Test class). Also the nested function is actually called in that version, unlike yours.
A function inside of a function is commonly used for closures.
Here's an example using the built-in
sum(). It defines
start once and uses it from then on:
def sum_partial(start): def sum_start(iterable): return sum(iterable, start) return sum_start
1) sum_with_3 = sum_partial(3) sum_with_1<function sum_start at 0x7f3726e70b90> sum_with_3<function sum_start at 0x7f3726e70c08> sum_with_1((1,2,3))7sum_with_3((1,2,3))9sum_with_1 = sum_partial(
Built-in python closure
functools.partial is an example of a closure.
From the python docs, it's roughly equivalent to:
def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*(args + fargs), **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc
(Kudos to @user225312 below for the answer. I find this example easier to figure out, and hopefully will help answer @mango's comment.)