Deferring Calls with Lambdas and Object References
More typically, lambdas are used to provide an indirection layer that passes along extra
data to a callback handler (I omit pack and mainloop calls in the following snippets for
simplicity):
def handler(A, B): # would normally be called with no args
...use A and B...
X = 42
Button(text='ni', command=(lambda: handler(X, 'spam'))) # lambda adds arguments
Although tkinter invokes command callbacks with no arguments, such a lambda can be
used to provide an indirect anonymous function that wraps the real handler call and
passes along information that existed when the GUI was first constructed. The call to
the real handler is, in effect, deferred, so we can add the extra arguments it requires.
Here, the value of global variable X and string 'spam' will be passed to arguments A and
B, even though tkinter itself runs callbacks with no arguments. The net effect is that the
lambda serves to map a no-argument function call to one with arguments supplied by
the lambda.
If lambda syntax confuses you, remember that a lambda expression such as the one in
the preceding code can usually be coded as a simple def statement instead, nested or
otherwise. In the following code, the second function does exactly the same work as
the prior lambda—by referencing it in the button creation call, it effectively defers
invocation of the actual callback handler so that extra arguments can be passed:
def handler(A, B): # would normally be called with no args
...use A and B...
X = 42
def func(): # indirection layer to add arguments
handler(X, 'spam')
Button(text='ni', command=func)
To make the need for deferrals more obvious, notice what happens if you code a handler
call in the button creation call itself without a lambda or other intermediate function—
the callback runs immediately when the button is created, not when it is later clicked.
That’s why we need to wrap the call in an intermediate function to defer its invocation:
def handler(name):
print(name)
Button(command=handler('spam')) # BAD: runs the callback now!
Using either a lambda or a callable reference serves to defer callback invocation until
the event later occurs. For example, using a lambda to pass extra data with an inline
function definition that defers the call:
def handler(name):
print(name)
384 | Chapter 7: Graphical User Interfaces