from tkinter import * # get base widget set
from dialogTable import demos # button callback handlers
from quitter import Quitter # attach a quit object to me
class Demo(Frame):
def init(self, parent=None):
Frame.init(self, parent)
self.pack()
Label(self, text="Basic demos").pack()
for key in demos:
func = (lambda key=key: self.printit(key))
Button(self, text=key, command=func).pack(side=TOP, fill=BOTH)
Quitter(self).pack(side=TOP, fill=BOTH)
def printit(self, name):
print(name, 'returns =>', demos[name]()) # fetch, call, print
if name == 'main': Demo().mainloop()
This script builds the same main button-bar window, but notice that the callback han-
dler is an anonymous function made with a lambda now, not a direct reference to dialog
calls in the imported dialogTable dictionary:
# use enclosing scope lookup
func = (lambda key=key: self.printit(key))
We talked about this in the prior chapter’s tutorial, but this is the first time we’ve
actually used lambda like this, so let’s get the facts straight. Because button-press call-
backs are run with no arguments, if we need to pass extra data to the handler, it must
be wrapped in an object that remembers that extra data and passes it along, by deferring
the call to the actual handler. Here, a button press runs the function generated by the
lambda, an indirect call layer that retains information from the enclosing scope. The
net effect is that the real handler, printit, receives an extra required name argument
giving the demo associated with the button pressed, even though this argument wasn’t
passed back from tkinter itself. In effect, the lambda remembers and passes on state
information.
Notice, though, that this lambda function’s body references both self and key in the
enclosing method’s local scope. In all recent Pythons, the reference to self just works
because of the enclosing function scope lookup rules, but we need to pass key in ex-
plicitly with a default argument or else it will be the same in all the generated lambda
functions—the value it has after the last loop iteration. As we learned in Chapter 7,
enclosing scope references are resolved when the nested function is called, but defaults
are resolved when the nested function is created. Because self won’t change after the
function is made, we can rely on the scope lookup rules for that name, but not for loop
variables like key.
Dialogs | 435