Python closure with side-effects
Asked Answered
P

2

10

I'm wondering if it's possible for a closure in Python to manipulate variables in its namespace. You might call this side-effects because the state is being changed outside the closure itself. I'd like to do something like this

def closureMaker():
  x = 0
  def closure():
    x+=1
    print x
  return closure

a = closureMaker()
a()
1
a()
2

Obviously what I hope to do is more complicated, but this example illustrates what I'm talking about.

Preconceive answered 3/7, 2011 at 23:41 Comment(2)
I'd mark this as a duplicate of other questions, except the other questions should really be marked a duplicate of this one; this question is quite simple and to-the-point and well-written. But also see #142142Misogynist
So there is no way to merge two or more questions? ;pRepel
P
17

You can't do exactly that in Python 2.x, but you can use a trick to get the same effect: use a mutable object such as a list.

def closureMaker():
    x = [0]
    def closure():
        x[0] += 1
        print x[0]
    return closure

You can also make x an object with a named attribute, or a dictionary. This can be more readable than a list, especially if you have more than one such variable to modify.

In Python 3.x, you just need to add nonlocal x to your inner function. This causes assignments to x to go to the outer scope.

Palmerpalmerston answered 3/7, 2011 at 23:47 Comment(5)
Please explain why? I'm trying to find something about this in the python docs.Repel
@André: PEP 3104 is informative, if technical: python.org/dev/peps/pep-3104Judiciary
To me, it seems like it should work either way. I just read this: "If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name."Repel
Ah, so when you try to assign to x in the example given in the question - it doesn't work because you try to rebind the variable? Sneaky.Repel
@André: When a variable is assigned to in a function (this includes augmented assignment operators such as +=), then it is made a local variable of that function. So in the original code, x is a local variable of closureMaker (because of x=0), and another x is made a local variable of closure (because of x+=1). When using a list instead, there is no direct assignment to x in closure, so it uses the same variable as closureMaker.Palmerpalmerston
M
5

What limitations have closures in Python compared to language X closures?

nonlocal keyword in Python 2.x

Example:

def closureMaker():
     x = 0
     def closure():
         nonlocal x
         x += 1
         print(x)
     return closure
Misogynist answered 4/7, 2011 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.