lambda

Alex Martelli aleaxit at yahoo.com
Thu May 24 04:12:49 EDT 2001


"Laura Creighton" <lac at cd.chalmers.se> wrote in message
news:mailman.990635563.6483.python-list at python.org...
> I use lambda for things like this:
>
> if __name__ == '__main__':
>     root = Tkinter.Tk()
>     w = Tkinter.Button(root, text='This is a very green button', width=
30, fg='green')
>
>     buttonList = (
>         ['show', lambda x = w: x.grid(row=0, col=0, columnspan= 5)],
>         ['pink', lambda x = w: x.configure(fg='pink')],
>         ['yellow', lambda x = w: x.configure(bg='yellow')],
>         ['Exit', root.destroy],
>         )
>     column = 0
>     for txt, cmd in buttonList:
>         button = Tkinter.Button(root, text = txt, command = cmd)
>         button.grid(row=1, col=column, sticky = 'w')
>         column = column + 1
>     root.mainloop()
>
> If I had just used w.grid up there I would get a yellow button with pink
> text.   This form is concise.  What do the lambda dislikers suggest I do
> instead?  (This is a serious question)

The named-function approach would be no less concise here:

    def show(): w.grid(row=0, col=0, columnspan=5)
    def pink(): w.configure(fg='pink')
    def yellow(): w.configure(bg='yellow')
    def Exit(): root.destroy()
    buttonList = show, pink, yellow, Exit
    column = 0
    for act in buttonList:
        button=Tkinter.Button(root, text=act.__name__, command=act)
        button.grid(row=1, col=column, sticky='w')
        column += 1
    root.mainloop()

Concision-promoting nested scopes and += help, but I think you
do save a couple characters anyway -- haven't bothered counting:-).

Seriously, the peculiarity here is that all of the button-texts
are acceptable as local function-names, so the def statements
play a dual role: define the codeblock to be run as the command
AND the name that codeblock goes by, to show on the button.  As
soon as you needed to have a button show text such as
    'pink fg'
or
    'yellow bg'
i.e. with a space inside, or anything but ASCII alphanumerics,
this wouldn't generalize -- you'd have to separately record
up to TWO 'names' for each action, in this case.  For example,
the buttonList might have to be defined as:
    buttonList = show, (pink, 'pink fg'), yellow, (root.destroy, 'Exit')
and the loop would be:
    for act in buttonList:
        try: cmd, txt = act
        except: cmd = act; txt = act.__name__
        button = Tkinter.Button(root, text=txt, command=cmd)
etc -- where I've also taken advantage of cases in which you
DO have a ready no-arguments callable such as root.destroy
to use, since now you don't need to wrap it into a function
JUST to change the button-text.  Some would think this a
"tricky" approach in some ways, but it seems reasonable
style to me.

OTOH, the lambda approach doesn't generalize without refactoring
on ANOTHER axis -- that of needing more than just an expression
as a button's action... when in the course of development or
maintenance it turns out that, e.g., "yellow" also needs to
increment a "global yellow count" each time it's clicked, the
lambda approach does require you to substitute a named local
function instead, while this function-approach affords more
immediate localized refactoring -- just change the function
body for the existing 'def yellow():'.

I understand and respect the argument "as long as we have
lambda in the language, migth as well make use of it", at
least in cases where its strong limitations don't byte (or
not too badly:-).  But, in my personal opinion, using
named (local) functions instead of lambda is not really
a big problem -- it may have pluses and minuses, but the
minuses tend to be smaller than the pluses in practice
(in my limited experience... I hardly ever code lambdas
these days, having gotten into the habit of naming my
functions anyway:-).  Again IMHO, the language would be
(marginally) better off without lambda, which does not
"fully carry its weight" (maybe it would, alternatively,
be better off with a _more powerful_ lambda, able to
express a block of statements rather than just an
expression, but I do not know if the resulting complexity
would have a net positive return).  Not having lambda
would promote the "one obvious way to do it" mantra:-).

I don't consider the issue a major one either way... no
doubt NOT worth the hassle of a backwards incompatibility!-)


Alex






More information about the Python-list mailing list