Sign in to follow this  
jwezorek

Python closures, me no understand

Recommended Posts

In the following code:
def count_if( func, seq):
    count = [0]
    def count_func( x ):
        if ( func(x) ):
            count[0] += 1
    for x in seq:
        count_func(x)
    return count[0]
why do I have to make count a one element list? (obviously I could implement this without a closure I'm just trying to understand how they work.) Edited by jwezorek

Share this post


Link to post
Share on other sites
This
[source lang="python"]
def count_if( func, seq):
count = 0
def count_func( x ):
if ( func(x) ):
count += 1
for x in seq:
count_func(x)
return count
[/source]
yields the error "UnboundLocalError: local variable 'count' referenced before assignment." When I google that I see people talking about this sort of thing but I haven't seen a clear explanation.

Share this post


Link to post
Share on other sites
I barely know Python, but [url="http://stackoverflow.com/questions/2516652/scoping-problem-in-recursive-closure"]this StackOverflow thread[/url] seems to describe the problem well enough to me. Basically: if you assign to a variable, that variable is created in the local scope, even if there is an identifier with the same name visible from an enclosing scope. Consequently, if you just read from a captured variable, things are dandy. But if you perform an assignment, even after the read, then it will assume that all references in that (enclosed) scope refer to a closure local. Apparently this is remedied (not very nicely, it has to be said) in Python 3.x.

Share this post


Link to post
Share on other sites
[quote name='TheUnbeliever' timestamp='1329360666' post='4913547']
I barely know Python, but [url="http://stackoverflow.com/questions/2516652/scoping-problem-in-recursive-closure"]this StackOverflow thread[/url] seems to describe the problem well enough to me. Basically: if you assign to a variable, that variable is created in the local scope, even if there is an identifier with the same name visible from an enclosing scope. Consequently, if you just read from a captured variable, things are dandy. But if you perform an assignment, even after the read, then it will assume that all references in that (enclosed) scope refer to a closure local. Apparently this is remedied (not very nicely, it has to be said) in Python 3.x.
[/quote]
But then why does the list version work? ... Oh, I guess I see, because count[0] += 1 does not tell python to create a one element list if count doesn't exist; if count doesn't exist count[0] += 1 is an error. if a list version of count exists *only* in an enclosing scope and you attempt this assignment python assumes you mean that one?

Share this post


Link to post
Share on other sites
You can't assign to 'count' (and have it refer to the same one) but you can modify the list it identifies. So, whilst you can't assign a new list to (the enclosing scope's) 'count', you can increment the first value in the list. You want to distinguish between the location 'count' and the value stored there.

Share this post


Link to post
Share on other sites
Oh, okay, so if 'count' was any kind of mutable type the enclosed scope can mutate it ... so the enclosed scope basically has access to count's value but doesn't have a reference to count itself.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this