Using the CPython implementation of Python 3.9.16 consider the following codes
def foo_a():
x = 1
fun = (lambda _x: lambda: print(_x))(x)
x = 2
return fun
def foo_b():
x = 1
fun = lambda _x=x: print(_x)
x = 2
return fun
fa = foo_a()
fb = foo_b()
where I've used two different methods for forcing early binding of x
. I believe these are semantically equivalent, however I notice that the resulting functions have different closures.
print(fa.__closure__) # (<cell at 0x0000025CED84BFD0: int object at 0x0000025CE9E36930>,)
print(fb.__closure__) # None
In the case of fa
I can access the local _x
variable using fa.__closure__[0].cell_contents
, but where is the local _x
stored in fb
if not inside its closure?
In your first example, _x
is a free variable whose value is found in a non-local scope carried by the inner function via a closure. (Informally, we say the inner function closes over the variable _x
in the outer function.)
In your second example, _x
is a local variable assigned at call time by an argument to fun
, or if none is provided, from a default value stored in the function itself.
Your use of both functions is the same, but if you received a reference to the inner function in the first example, it would be "harder" to change the value of _x
(you'd have to poke around in the closure itself; closures are, for better or worse, mutable) than it would be to change the value of _x
in the second example (you would just pass a different argument).