must be accessed again later, during event processing. Because tkinter calls the lambda
function later with no arguments, all its defaults are used.
This was not an issue in the original version of this example because name X lived in
the global scope, and the code of the lambda will find it there when it is run. When
nested within a function, though, X may have disappeared after the enclosing function
exits.
Passing in enclosing scope values with automatic references
While they can make some external dependencies more explicit, defaults are not usually
required (since Python 2.2, at least) and are not used for this role in best practice code
today. Rather, lambdas simply defer the call to the actual handler and provide extra
handler arguments. Variables from the enclosing scope used by the lambda are auto-
matically retained, even after the enclosing function exits.
The prior code listing, for example, can today normally be coded as we did earlier—
name X in the handler will be automatically mapped to X in the enclosing scope, and so
effectively remember what X was when the button was made:
def makegui():
X = 42 # X is retained auto
Button(text='ni', command=(lambda: handler(X, 'spam'))) # no need for defaults
We’ll see this technique put to more concrete use later. When using classes to build
your GUI, for instance, the self argument is a local variable in methods, and is thus
automatically available in the bodies of lambda functions. There is no need to pass it
in explicitly with defaults:
class Gui:
def handler(self, A, B):
...use self, A and B...
def makegui(self):
X = 42
Button(text='ni', command=(lambda: self.handler(X, 'spam')))
Gui().makegui()
mainloop()
When using classes, though, instance attributes can provide extra state for use in call-
back handlers, and so provide an alternative to extra call arguments. We’ll see how in
a moment. First, though, we need to take a quick non-GUI diversion into a dark corner
of Python’s scope rules to understand why default arguments are still sometimes nec-
essary to pass values into nested lambda functions, especially in GUIs.
But you must still sometimes use defaults instead of enclosing scopes
Although you may still see defaults used to pass in enclosing scope references in some
older Python code, automatic enclosing scope references are generally preferred today.
In fact, it seems as though the newer nested scope lookup rules in Python automate
Adding User-Defined Callback Handlers | 387