newbie: binding args in callbacks

Alex Martelli aleax at aleax.it
Wed Jul 10 10:29:01 EDT 2002


Edward K. Ream wrote:

> This question was asked a while back, and I don't see it in the FAQ or
> in the archives...
> 
> I would like to create a set of Tkinter callbacks that vary only in the
> bindings of a single argument. For example,  I would like to do:
> 
> for val in vals:
>   b = Tk.Button(...,command=self.myCallback(val))
> 
> But this doesn't work: it executes callback, rather than returning the
> callback function with the second arg bound to val.

Right.


> I also tried:
> 
> for val in vals:
>  callback=lambda None:self.myCallback(x=val)
>  b = Tk.Button(...,command=callback)
> 
> But that doesn't quite work either.  When the callback executes I get:
> TypeError: <lambda>() takes exactly 1 argument (0 given)

Indeed, you specified a lambda taking a single argument (accidentally
named None just like the popular builtin object) and ignoring it.


> Can someone explain how to do this?  Thanks.

My suggestion:

    def makeCallback(self, val):
        def callback(self=self, val=val): return self.myCallback(val)
        return callback

and then:

    b = Tk.Button(..., command=self.makeCallback(val) )


You don't need the default-values trick in Python 2.2 -- so, if
that's what you're using, it would be better to use, instead:

    def makeCallback(self, val):
        def callback(): return self.myCallback(val)
        return callback


If you're insistent on using lambda (only sensible reason being that
you made a bet about lambda being used here), you _can_, e.g. in 2.2:

    def makeCallback(self, val):
        return lambda: self.myCallback(val)

but I think the nested-function approach is more readable.


Alex




More information about the Python-list mailing list