9

In JS, we can write closure like:

function f(){
var a=0;
function g(){
    alert(a++);
}
return g;
}
g=f()
g()

However, if I write following code in python

def f():
    a=0
    def g():
        a+=1
        print a
    return g
g=f()
g()

Then I get UnboundedLocalError.

Can anyone tell me the difference between closure in python and JS?

2
  • 3
    Do you really believe that this difference will explain what you're seeing? Commented May 6, 2011 at 10:38
  • I think so. Direct explanation of the observed result is also welcome Commented May 6, 2011 at 16:10

2 Answers 2

12

When you use a += 1 in Python it refers to a local (uninitialized) variable in scope of g function. Basically you can read variables from upper scopes, but if you try to write it will refer to a variable in most recent scope. To make it work like you want you have to use nonlocal keyword that is only present Python 3. In Python 2 you can't do that as far as I know, unless the variable you're trying to change is is global, then global keyword comes to the rescue.

def f():
    a=0
    def g():
        nonlocal a
        a+=1
        print a
    return g
g=f()
g()
Sign up to request clarification or add additional context in comments.

4 Comments

In Python 2, a = [0] and a[0] += 1 makes it work. This works because item assignment (along with member and slice assignment) doesn't count as overwriting a variable, you instead change state of an object (under the hood, you call a method).
Looks like an ugly hack but it is indeed a way out.
This is related to the fact that integers are immutable: a += 1 is the same as a = a + 1 for ints. It binds the name a to a new expression instead of modifying the object currently named by a, like a list operation does.
It is an ugly hack, That's why Python3 adds nonlocal afterall. Usually it is better to design the code to not need this kind of hack, but sometimes the complication of the alternative could be works than using the hacky way
2

Version for python 2:

def f():
    a=0
    def g():
        g.a+=1
        print g.a

    g.a=a
    return g
g=f()
g()

2 Comments

this is different from expected: calling g() twice return the same result
@user607722 fixed the problem code. Tested repeated calls. It might be better coded as a generator though to simplify keeping state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.