In general, when the inner function is small and you want to make it clear that it's only useful to the enclosing function. Alternatively, when you need to return a function. The latter scenario is trivial since generally the inner function relies on variables in the enclosing functions's scope, so declaring it anywhere else isn't an option. You might be able to use a lambda in that case, but anything longer than one expression would need a full function declaration.
Without the implementations it's hard to say which one you should choose in this case. I would hasten to add that you don't have to put everything in a class either.
Answer from Doval on Stack ExchangeNested Function Best Practices (Python)
code quality - When to use python function nesting? - Software Engineering Stack Exchange
python - Is nested function a good approach when required by only one function? - Stack Overflow
refactoring - Is it good to use inner function in a python function to make the logic clear? - Stack Overflow
I have been writing a class which resembles a binary tree and have been looking to clean up my code a bit and found my way to nested functions. I understand the basic logic behind them and what not, my question is more on how they are used within custom objects.
For example, if i am trying to print the tree in-order and i do something like:
def print_inorder(self):
def display(node, level):
if not node:
return
display(node.left_child, level + 1)
print('\t' * level, node)
display(node.right_child, level + 1)
display(self.root, 0)Would this be correct best practices? The thing that is somewhat confusing to me is switching from using 'self.' for functions relating to the object, to an inner function that doesn't need a 'self.' even though an object is technically calling it. is this already best practice or should I still be using the 'self.'? or is there a better convention to use all together? Thanks.
In general, when the inner function is small and you want to make it clear that it's only useful to the enclosing function. Alternatively, when you need to return a function. The latter scenario is trivial since generally the inner function relies on variables in the enclosing functions's scope, so declaring it anywhere else isn't an option. You might be able to use a lambda in that case, but anything longer than one expression would need a full function declaration.
Without the implementations it's hard to say which one you should choose in this case. I would hasten to add that you don't have to put everything in a class either.
TL;DR: Use function nesting when you need the characteristics of function nesting
Function Nesting Use Cases (mostly functional idioms, almost certainly incomplete since it's off the top of my head):
- closures
- function factory (programmatic function creation based on parameters)
- creating functions by calling functool.partial
- creating functions by using lambda
- any other reasons you need to create functions during call time
Trade-offs:
- functions are strongly coupled
- the code is always called (unless it's in an if block)
- additional code complexity
- additional runtime cost (potentially, because the inner function get's re-defined with every call to the outer function)
- much harder to extend
- much harder to introspect on the inner function defintion
>>> def sum(x, y):
... def do_it():
... return x + y
... return do_it
...
>>> a = sum(1, 3)
>>> a
<function do_it at 0xb772b304>
>>> a()
4
Is this what you were looking for? It's called a closure.
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. _method_b.
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.
Update:
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 Timer
print(min(Timer(stmt='obj.separate(42)', setup=setup).repeat())) # -> 0.24479823284461724
print(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.
Use lambda if it's a simple function.
Use an inner function if it is complex and you don't want to make it "public".
Use a "private" method if you want to mark it hidden and uses members of the instance.
Use a method if you want to make it "public" and uses members of the instance.
Use a class method if it uses class members.
And lastly use a global function if it's general enough to be used by other classes/functions.
You forgot one point in your pro/cons list: testability. Keeping some_logic out of foo makes it testable in isolation, which is important if it's indeed a "complex" (hence very probably critical) function.
As a general rule, only use inner functions when you have both of those conditions: it's trivial stuff and passing the required context (the 'outer' function's context) would be a pain.
(nb: I'm of course not talking about using inner functions for closures - like in a decorator - here).
Been loving Python for 7+ years not and still going strong. I recently found myself writing more and more inner functions to encapsulate logic easier and make otherwise rather polluting/dead functions stick out less.
I like it, because it allows me to write way cleaner and less bloated code – clustering helper-functions to only where they need to be. Also decreases cognitive load considerably by not having to keep track on where a helper function is being used.
But it has gotten to a point where I'm genuinely concerned, because I have also started defining lambdas in inner-functions too! I know lambda shouldn't be used and PEP checker complains too, but it's so handy when combined with list comprehensions…
What are your thoughts on this?
Do you use nested functions yourself or do you consider it bad practice? Where else do you put helpers?
An example would be the following code:
def send_mail(
*,
subject: str,
body_plain: str,
send_to: Union[List[str], str, List[User], User],
send_cc: Optional[Union[List[str], str, List[User], User]] = None,
send_bcc: Optional[Union[List[str], str, List[User], User]] = None,
reply_to: Optional[Union[List[str], str, List[User], User]] = None
...
) -> None:
def _process_recipients(*, recipients: Optional[Union[List[str], str, List[User], User]]) -> List[str]:
""" Process various inputs for `send_to`, `send_cc` and `send_bcc` to a normalized
output that can be used by the emailing instance aka a list of emails """
_user_to_email = lambda x: x.email if isinstance(x, User) else x # transform user objects to mail
if not recipients: return [] # recipients are empty
if isinstance(recipients, str) or isinstance(recipients, User):
recipients = [recipients]
return [_user_to_email(recipient) for recipient in recipients]
...
send_to = _process_recipients(recipients=send_to)
send_cc = _process_recipients(recipients=send_cc)
send_bcc = _process_recipients(recipients=send_bcc)
...