Button(command=(lambda: handler('spam'))) # OK: wrap in a lambda to defer
is always equivalent to the longer, and to some observers less convenient, double-
function form:
def handler(name):
print(name)
def temp():
handler('spam')
Button(command=temp) # OK: refence but do not call
We need only the zero-argument lambda or the zero-argument callable reference,
though, not both—it makes no sense to code a lambda which simply calls a function if
no extra data must be passed in and only adds an extra pointless call:
def handler(name):
print(name)
def temp():
handler('spam')
Button(command=(lambda: temp())) # BAD: this adds a pointless call!
As we’ll see later, this includes references to other callables like bound methods and
callable instances which retain state in themselves—if they take zero arguments when
called, we can simply name them at widget construction time, and we don’t need to
wrap them in a superfluous lambda.
Callback Scope Issues
Although the prior section’s lambda and intermediate function techniques defer calls
and allow extra data to be passed in, they also raise some scoping issues that may seem
subtle at first glance. This is core language territory, but it comes up often in practice
in conjunction with GUI.
Arguments versus globals
For instance, notice that the handler function in the prior section’s initial code could
also refer to X directly, because it is a global variable (and would exist by the time the
code inside the handler is run). Because of that, we might make the handler a one-
argument function and pass in just the string 'spam' in the lambda:
def handler(A): # X is in my global scope, implicitly
...use global X and argument A...
X = 42
Button(text='ni', command=(lambda: handler('spam')))
Adding User-Defined Callback Handlers | 385