artemonster
artemonster

Reputation: 763

When python closures are exactly doing their capture?

Here is a rather self-explanatory code snippet in python:

globl = 1
def foo():
    def bar(): 
        return free+capture
    capture = globl #not seen, when bar is defined
    return bar

free = 2
a = foo()
globl = 4
b = foo()
print(a()) #3
print(b()) #6
print(a.__closure__[0].cell_contents) # 1
print(b.__closure__[0].cell_contents) # 4 

When 'bar' is defined, both 'free' and 'captured' variables are free. they do not exist in parent envirionment, neither in root. When 'bar' returned from 'foo', 'capture' will be captured. From a stack!
So I assume python closes over environment on return of a function. Why is that the case? Why not on definition time of 'bar'? Same snippet also works if we replace bar with lambda:

bar = lambda : free+capture

Upvotes: 3

Views: 93

Answers (1)

Yilmaz
Yilmaz

Reputation: 49401

at compile-time, when python encounters a function, it makes some determinations. It looks at everything in the function, it does not create a scope or a namespace but it determines which variables are going to be local or nonlocal.

When you run foo(), which means at run-time of foo, bar function gets created and python determines "free" and "capture" as non-local, therefore bar already has a reference to free variables.

"free" and "capture" are in two different scopes but always reference the same "value". When python determines the local variables of "bar", it creates a cell object.

enter image description here

So when outer function "foo" finishes running, this "Cell" object still exists so when inner function "bar" is called, it still gets the same value.

Upvotes: 2

Related Questions