Lambdas and variables

James Henderson james at logicalprogression.net
Tue Jul 27 20:32:42 EDT 2004


John Fouhy wrote:

> So I'm trying to generate Tkinter callback functions on the fly, but
> it's not working, and I don't understand what's going on.
> 
> Here is an example program:
> 
> --------------------------
> from Tkinter import *
> 
> def printSomething(x):
>     print x
> 
> tk = Tk()
> stuff = ['foo', 'bar', 'baz', 'zif', 'zaf', 'zof']
> 
> for x in stuff:
>     l = Label(tk, text=x)
>     l.pack()
>     l.bind('<Enter>', lambda e: printSomething(x))
> 
> tk.mainloop()
> --------------------------
> 
> The desired behaviour is that the program should print to stdout the
> text on the label whenever the mouse enters that widget.
> 
> However, what actually happens is that it prints out 'zof' whenever
> the mouse enters any of the widgets.
> 
> To further confuse me, if I add a bit of indirection:
> 
> --------------------------
> from Tkinter import *
> 
> def makeFunction(x):
>     return lambda e: printSomething(x)
> 
> def printSomething(x):
>     print x
> 
> tk = Tk()
> stuff = ['foo', 'bar', 'baz', 'zif', 'zaf', 'zof']
> 
> for x in stuff:
>     l = Lable(tk, text=x)
>     l.pack()
>     l.bind('<Enter>', makeFunction(x))
> 
> tk.mainloop()
> --------------------------
> 
> ...then everything works as it should.
> 
> I am running Python 2.3.4.
> 
> Can anyone explain this to me?

Derek has answered your question, but you might also be interested to 
know that your first example would work with one small change:

for x in stuff:
     l = Label(tk, text=x)
     l.pack()
     l.bind('<Enter>', lambda e, x=x: printSomething(x))

That is, "x" is passed as a default parameter to the lambda, which is 
slightly more concise that your defining of an extra function.  This 
works because default parameters are evaluated once and for all at the 
time of a function's definition.

James




More information about the Python-list mailing list