When python closures are exactly doing their capture?

Viewed 57

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
1 Answers

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.

Related