7

Say I have a list of strings: obj = ['One','Two','Three'], how would I be able to turn each value in this list into a function where they all carry out very similar functions? For example:

def one():
    print("one")

def two():
    print("two")

def three():
    print("three")

Now I know you can define the functions beforehand and use a dictionary (as shown below), but say I wanted many functions to be created, it would take a lot of code to do so and therefore I would like to find out if there is a shorter way I can go about this.

import tkinter as tk

def one():
    print("one")

def two():
    print("two")

def three():
    print("three")

obj = ['One','Two','Three']
func = {'One': one, 'Two': two, 'Three': three}

def create_btn():
    btns =  {}
    for i in obj:
        text = i
    for col in range(1):
        for row in range(len(obj)):
            btns[row, col] = tk.Button(canvas, text=str(text),
                                       command=func[i]).grid(column=col,
                                                                 row=row)
            btns[row, col] = canvas.create_window(50, row,
                                                  window = btns[row, col])
            canvas.pack()


root = tk.Tk()          
root.geometry = ("750x600")

btn_frame = tk.Frame(root)
canvas = tk.Canvas(root)

create_btn()
root.mainloop()
  • Use `map` and a lambda function that produces lambda functions. `l = list(map(lambda x: lambda: print(x), obj))` then `l[0]()` prints `One` – Patrick Haugh Jan 27 '17 at 18:06
  • Related: [Python dynamic function creation with custom names](http://stackoverflow.com/questions/13184281/python-dynamic-function-creation-with-custom-names) – blacksite Jan 27 '17 at 18:10

2 Answers2

7

Use a closure:

>>> def print_me(string):
...     def inner():
...         print(string)
...     return inner
...
>>> functions = [print_me(s) for s in obj]
>>> functions[0]()
One
>>> functions[1]()
Two
>>> functions[2]()
Three

Maybe a dict would be more convenient:

>>> functions = {s:print_me(s) for s in obj}
>>> functions['One']
<function print_me.<locals>.wrapper at 0x102078bf8>
>>> functions['One']()
One
>>>
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • This works, but say I wanted to use each function for a button, how would I remove the parentheses to be able to use `command=`? –  Jan 27 '17 at 18:20
  • @Ernxst I'm not sure what you mean "remove the parentheses", that was just me demonstrating *calling* those functions. But functions are first-class objects in Python. They are *in the list*. To access a function, use `function[1]` to get the second one in the list, for example. – juanpa.arrivillaga Jan 27 '17 at 18:24
  • I know I can index the list for the function, but I wanted to create several buttons with different functions so I can't really using list-indexing to set their `command`. –  Jan 27 '17 at 18:26
  • @Ernxst It seems straightforward to me... loop over the list, attatch function as needed: `command=function[i]` or whatever. You can also place them in a dictionary if needed. – juanpa.arrivillaga Jan 27 '17 at 18:28
  • Never mind, I just wasn't paying attention to it properly –  Jan 27 '17 at 18:48
1

if you want to manage the names too, a simple solution with exec :

L=['one','two','three']
prog='def xxx():print("xxx")'
for name in L:
    exec(prog.replace('xxx',name))

three functions are defined.

>>>two()
two
>>>
B. M.
  • 18,243
  • 2
  • 35
  • 54