def normal():
def action():
return spam # really, looked up when used
spam = 'ni'
return action
act = normal()
print(act()) # also prints 'ni'
As this implies, the enclosing scope name isn’t resolved when the nested function is
made—in fact, the name hasn’t even been assigned yet in this example. The name is
resolved when the nested function is called. The same holds true for lambdas:
def weird():
spam = 42
return (lambda: spam * 2) # remembers spam in enclosing scope
act = weird()
print(act()) # prints 84
So far, so good. The spam inside this nested lambda function remembers the value that
this variable had in the enclosing scope, even after the enclosing scope exits. This pat-
tern corresponds to a registered GUI callback handler run later on events. But once
again, the nested scope reference really isn’t being resolved when the lambda is run to
create the function; it’s being resolved when the generated function is later called. To
make that more apparent, look at this code:
def weird():
tmp = (lambda: spam * 2) # remembers spam
spam = 42 # even though not set till here
return tmp
act = weird()
print(act()) # prints 84
Here again, the nested function refers to a variable that hasn’t even been assigned yet
when that function is made. Really, enclosing scope references yield the latest setting
made in the enclosing scope, whenever the function is called. Watch what happens in
the following code:
def weird():
spam = 42
handler = (lambda: spam * 2) # func doesn't save 42 now
spam = 50
print(handler()) # prints 100: spam looked up now
spam = 60
print(handler()) # prints 120: spam looked up again now
weird()
Now, the reference to spam inside the lambda is different each time the generated func-
tion is called! In fact, it refers to what the variable was set to last in the enclosing scope
at the time the nested function is called, because it is resolved at function call time, not
at function creation time.
Adding User-Defined Callback Handlers | 389