Tkinter Puzzler

Eric Brunel eric_brunel at despammed.com
Fri Jan 7 06:03:14 EST 2005


Tim Daneliuk wrote:
> I am trying to initialize a menu in the following manner:
> 
> for entry in [("Up", KeyUpDir), ("Back", KeyBackDir), ("Home", 
> KeyHomeDir), ("Startdir", KeyStartDir), ("Root", KeyRootDir)]:
> 
>     func = entry[1]
>     UI.ShortBtn.menu.add_command(label=entry[0], command=lambda: 
> func(None))
> 
> However, at runtime, each of the menu options binds to the *last* function
> named in the list (KeyStartDir).
> 
> Explicitly loading each entry on its own line works fine:
> 
> UI........command=lambda:KeyWHATEVERDir(None)
> 
> Any ideas why the first form does not fly?

This has nothing to do with Tkinter, but only with the way nested scopes work: 
to put it roughly, your "lambda: func(None)" only knows about the *name* func, 
which is not actually evaluated until the button is pressed. And when the button 
is pressed, the name func is bound to the last command in the loop.

To do what you want, change your code to:

for entry in (...):
   UI.ShortBtn.menu.add_command(
     label=entry[0],
     command=lambda func=entry[1]: func(None)
   )

This way, the value for the func parameter is evaluated when the function is 
defined and not when it is called.

HTH
-- 
- Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com



More information about the Python-list mailing list