-1

What (if anything) is actually different between using a name in a nested function and passing a name to a nested function? If there's no difference, which is preferred by convention?

def foo(bar):
    def put():
        bar.append('World!')
        print(', '.join(bar))
    put()
foo(['Hello'])

versus

def foo(bar):
    def put(bar):
        bar += ['World!']
        print(', '.join(bar))
    put(bar)
foo(['Hello'])
Ian
  • 1,062
  • 1
  • 9
  • 21
  • 1
    related: http://stackoverflow.com/questions/1261875/python-nonlocal-statement – NightShadeQueen Aug 07 '15 at 19:45
  • 1
    As the Zen of Python dictates, "Explicit is better than implicit.". In this case, explicitly passing the argument is clearer than having to guess where `bar` suddenly came from. – Wolph Aug 07 '15 at 19:54
  • Are you only talking about nested functions, and not closures? Meaning, are you not intending to return `put` as the return value of `foo`? – Cyphase Aug 07 '15 at 19:58
  • @Cyphase I am not talking about closures, unless that influences the choice between the alternatives. Thanks for clarifying. – Ian Aug 07 '15 at 20:00
  • Ian, I'll say upfront that I agree with @Wolph that explicit is better than implicit. That said though, is there a reason you need a nested function at all as opposed to defining it on it's own? That's the better option IMO. – Cyphase Aug 07 '15 at 20:03
  • @Cyphase Reason: it seems to me that defining `put` in the global scope, while only using it in `foo` is akin to `put` suddenly appearing. I guess "sudden" is subjective. – Ian Aug 07 '15 at 20:11
  • @Ian, using `put` somewhere else as well doesn't make it any less 'sudden' of an appearance in `foo`. I realize this is probably a made-up example, but in this case and many others, you don't even need a `put` function; just put the code for the `put` function directly in `bar`. Could you show an example closer to your actual usage? – Cyphase Aug 07 '15 at 20:16
  • @Ian, did one of the answers solve your problem? If so, please accept it :). – Cyphase Aug 10 '15 at 06:55

2 Answers2

1

Since you're only talking about nested functions, and not closures, unless you have a specific reason to have it be nested, I would recommend defining each function in the module scope:

def put(bar):
    bar += ['World!']
    print(', '.join(bar))


def foo(bar):
    put(bar)


foo(['Hello'])

If for some reason you do need it to be nested, it's better to pass in bar explicitly. However, if you do think you need it to be nested, ask about your reasoning first; there's a good chance that you don't. :)

Cyphase
  • 11,502
  • 2
  • 31
  • 32
0

The difference is that in the first one, bar variable is in a scope of the parent function, it can be used in the child function , unless you do assignment on it (This would be the case something similar to using global variables in function) . Example -

>>> def foo(bar):
...     def put():
...         bar = bar + ['World']
...         print(', '.join(bar))
...     put()
...
>>>
>>> foo(['Hello'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in foo
  File "<stdin>", line 3, in put
UnboundLocalError: local variable 'bar' referenced before assignment

In this case if you want to use the bar and assign to it as well, you need to use the nonlocal keyword , Example -

>>> def foo(bar):
...     def put():
...         nonlocal bar
...         bar = bar + ['World!']
...         print(', '.join(bar))
...     put()
...
>>> foo(['Hello'])
Hello, World!

Whereas in the second one, bar is a local variable to the put() function (because its an argument to it) and can be assigned without the above UnboundLocalError , Example -

>>> def foo(bar):
...     def put(bar):
...         bar = bar + ['World!']
...         print(', '.join(bar))
...     put(bar)
...
>>>
>>> foo(['Hello'])
Hello, World!

I would prefer explicitly passing the required arguments as done in the second case.

Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • If you don't assign to `bar` in the second case (either by using `bar.append` or `+=`) then `bar` is not local, right? Its value will change in the scope of foo after `put(bar)` as well. So in my snippets ... effectively no difference? – Ian Aug 08 '15 at 02:35
  • in second case, bar is always local to the inner function, irrespective of whether you assign or not. But yes in your particular example, bar being local or not , does not really make a difference. – Anand S Kumar Aug 08 '15 at 02:38