7

I'm wondering, how would I make a Tkinter (in Python) Menu that targets a function with arguments, such as foo("what")?

def foo(arg):
    print "Foo, %s." % arg

popup = Menu()
popup.add_command(label="Spam!", command=foo("spam")) # Doesn't work.
popup.add_command(label="Turkey!", command=foo("turkey")) # Doesn't work.
popup.post(50, 50)
Aqua the SeaWing
  • 333
  • 4
  • 16

2 Answers2

13

Command takes a function as argument, but foo("spam") gives the return value of foo when called with argument "spam". As a solution, you can use an anonymous function which calls foo("spam") as argument:

command=lambda: foo("spam")
fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
7

For this kind of stuff, especially event handlers and commands, an elegant solution is using the functools module's partial() method.

from functools import partial
...
command=partial(foo, "spam")

Partial is said to be faster than using lambda: Differences between functools.partial and a similar lambda?

Community
  • 1
  • 1
kartikg3
  • 2,590
  • 1
  • 16
  • 23
  • This approach seems to be the only one that works when, instead of `"spam"`, we have an iteration variable. E.g. `for elem in list : ... command=partial(foo, elem)` won't work using `lambda`. – logi-kal Dec 01 '18 at 15:12
  • 1
    @horcrux You can use lambda inside a loop, but you need to bind the current loop value to a keyword argument in your lambda. See https://stackoverflow.com/a/17677768/3714930 – fhdrsdg Dec 03 '18 at 07:36