3

Consider the following function, which we'd like to not be constant on integers a, but which always returns (1,2):

def foo(a):
    b = 1
    c = 2
    def bar(b,c):
        b = b + a
        c = c + a
    bar(b,c)
    return (b,c)

If I understand correctly, the idiomatic way to implement bar(b,c) would be to give it no parameters at all and declare b and c nonlocal inside its definition. I'm curious, however: how do we make an inner function have nonlocal effects on its parameters?

bastelflp
  • 9,362
  • 7
  • 32
  • 67

3 Answers3

3

As stated in this answer for Python 2.x:

Python doesn't allow you to reassign the value of a variable from an outer scope in an inner scope (unless you're using the keyword "global", which doesn't apply in this case).

This will return (2,3):

def foo(a):
    b = 1
    c = 2
    def bar(b,c):
        b = b + a
        c = c + a
        return b, c
    b, c = bar(b,c)
    return (b,c)

print(foo(1))
Community
  • 1
  • 1
bastelflp
  • 9,362
  • 7
  • 32
  • 67
2

Make b and c function attributes.

def foo(a):
    foo.b = 1
    foo.c = 2
    def bar():
        foo.b = foo.b + a
        foo.c = foo.c + a
    bar()
    return (foo.b,foo.c)

Notice you no longer pass b or c into the function bar.

John Howard
  • 61,037
  • 23
  • 50
  • 66
  • 4
    You may as well mark them `nonlocal`, for all the difference this makes. – Martijn Pieters Feb 11 '16 at 21:39
  • 2
    Also, if `bar` is shared outside of `foo`, then those attributes act like globals, any code can manipulate them and alter the outcome. They are **not** the same thing as parameters or `nonlocal` closures. – Martijn Pieters Feb 11 '16 at 21:40
2

Function parameters are always locals. You could pass in mutable objects however, and apply your operations to the indirectly referenced value:

def foo(a):
    b = [1]
    c = [2]
    def bar(b, c):
        b[0] += a
        c[0] += a
    bar(b, c)
    return (b[0], c[0])

The changes you make to the mutable object are shared with any other references to those objects, including locals in foo().

However, if you want something to be a closure, just make it a closure. There are no use cases for this that cannot be handled by nonlocal values and return.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343