LAMBDA IS IT USELESS?

Carel Fellinger cfelling at iae.nl
Thu Jul 12 11:48:45 EDT 2001


Sheila King <sheila at spamcop.net> wrote:
> I'm interested to see what responses you will get to this query, as I
> don't fully understand the lambda functions either. However, I'm
> currently working through the chapters on Tkinter in Programming Python,
> 2nd ed., and apparently, there are cases when issuing callbacks for
> events, that in order to be able to pass parameters to the callback
> function, one must use lambda functions.

I have'nt seen this question addressed yet, so I give it a try.

Tkinter callbacks are to be called when an event happens, like a mouse
click.  So callbacks have to be callable objects.

When you specify the callback in the widget creation call, clearly the
callback is not to be called yet, you only pass a callable object to
be called later when the triggering event happens.

Now suppose you want to `curry' that callback at specification time.
The straighforward way is to define a local function embedding the
curry you want to apply. And here you have a choice of naming that
function or using a nameless one.  Ofcourse you could equally well
use one of the class based currying methods discussed so often in
this newsgroup.


Example time:

   >>> from Tkinter import *
   >>> 
   >>> def p(s):
   ...     print "s='%s'" % s
   ... 
   >>> root = Frame(); root.pack()
   >>> b = Button(root, text="p", command=p)
   >>> b.pack()
   
pressing the button on the screen gives:

   Exception in Tkinter callback
   Traceback (most recent call last):
     File ".../Tkinter.py", line 1285, in __call__
       return apply(self.func, args)
   TypeError: p() takes exactly 1 argument (0 given)

ofcourse passing a parameter to p doesn't help us out:

   >>> b = Button(root, text="p", command=p("aap"))
   s='aap'

oeps, p is called directly

   >>> b.pack()

and pressing the second button has no effect what so ever.
So we have to use some currying trick, e.g. a local function:

   >>> def local_f(p=p): return p("local_f")
   >>> b = Button(root, text="local_f", command=f)
   >>> b.pack()

pressing the button gives:

   s='local_f'

Some peaple prefer nameless functions and use lambda's here, like:

   >>> b = Button(root, text="lambda", command=lambda x="lambda": p(x))
   >>> b.pack()

pressing the third button gives:

    s='lambda'

now let's acchieve the same with classes and callable instances.

   >>> class Curry:
   ... 	   def __init__(self, fun, *args):
   ... 	       self.fun = fun
   ... 	       self.args = args
   ... 	   def __call__(self, *args):
   ... 	       return self.fun(*(self.args + args))
   ... 
   >>> b = Button(root, text="curry", command=Curry(p, "spam and spam"))
   >>> b.pack()

pressing the forth button gives us:

   s='spam and spam'

if you want to try this running it from a script you need to add this:

   >>> root.mainloop()




-- 
groetjes, carel



More information about the Python-list mailing list