For that matter, A could be moved out to the global scope too, to remove the need for
lambda here entirely; we could register the handler itself and cut out the middleman.
Although simple in this trivial example, arguments are generally preferred to globals,
because they make external dependencies more explicit, and so make code easier to
understand and change. In fact, the same handler might be usable in other contexts, if
we don’t couple it to global variables’ values. While you’ll have to take it on faith until
we step up to larger examples with more complex state retention needs, avoiding glob-
als in callbacks and GUIs in general both makes them more reusable, and supports the
notion of multiple instances in the same program. It’s good programming practice, GUI
or not.
Passing in enclosing scope values with default arguments
More subtly, notice that if the button in this example was constructed inside a func-
tion rather than at the top level of the file, name X would no longer be global but would
be in the enclosing function’s local scope; it seems as if it would disappear after the
function exits and before the callback event occurs and runs the lambda’s code:
def handler(A, B):
...use A and B...
def makegui():
X = 42
Button(text='ni', command=(lambda: handler(X, 'spam'))) # remembers X
makegui()
mainloop() # makegui's scope is gone by this point
Luckily, Python’s enclosing scope reference model means that the value of X in the local
scope enclosing the lambda function is automatically retained, for use later when the
button press occurs. This usually works as we want today, and automatically handles
variable references in this role.
To make such enclosing scope usage explicit, though, default argument values can also
be used to remember the values of variables in the enclosing local scope, even after the
enclosing function returns. In the following code, for instance, the default argument
name X (on the left side of the X=X default) will remember object 42 , because the variable
name X (on the right side of the X=X) is evaluated in the enclosing scope, and the gen-
erated function is later called without any arguments:
def handler(A, B): # older Pythons: defaults save state
...use A and B...
def makegui():
X = 42
Button(text='ni', command=(lambda X=X: handler(X, 'spam')))
Since default arguments are evaluated and saved when the lambda runs (not when the
function it creates is later called), they are a way to explicitly remember objects that
386 | Chapter 7: Graphical User Interfaces