I have created a variable-length list containing several buttons:
buttonList = [tk.Button(command=record,
text=str((i % MONTH_LEN[TIME.month]) + 1))
for i in range(x)]
x
is the length of the list of buttons (PREDEFINED!).
MONTH_LEN
and TIME.MONTH
shouldn’t be needed of course; they’re just part of the text.
I want to be able to differentiate between the different buttons being clicked WITHOUT needing to create masses of functions.
The most important part to note is that record
should change a character in a string based on which button was clicked; the first button changes the first element in the string, the 20th button changes the 20th element in the string etc etc.
How can I achieve this? Is there a better way to go about this?
Use lambda functions
Here is an example:
import tkinter as tk
root = tk.Tk()
x = 20
my_list = ['a'] * x
def record(index):
my_list[index] = 'b'
print(''.join(my_list))
buttonList = [
tk.Button(
command=lambda index=i: record(index),
text=str(i),
)
for i in range(x)
]
for button in buttonList:
button.pack()
root.mainloop()
lambdas are a way to create “masses of functions” (as you put it) on the fly, without needing to give them names. The code lambda index=i: record(index)
is pretty much equivalent to the following code:
def noname(index=i):
return record(index)
Note that we have to create a keyword argument index
and set its default value to i
in order to “capture” the value of i
at each loop iteration. If we instead did lambda: record(i)
, it would look up the value of i in the global scope, which will be equal to its value on the last iteration.
Errata
record should change a character in a string based on which button was clicked
Python strings are not mutable, unlike in many other languages. You cannot change them element-by-element. Actually, you cannot change them at all. You have to use a mutable container like list
, and convert it to a string, as I did in my example.
Also, consider renaming buttonList
to button_list
. Using underscores is the convention in Python. You can read more about variable naming in PEP8.
One option is
functools.partial
to create function wrappers containing the currenti
value (record
must then be adjusted to accept the additionali
argument).Well yes you can, easiest solution with multiple examples on the web is to use a lambda function that’s passing an argument to your function.
Can you explain in baby terms? Functools is a new environment to me. Also, what would ‘record’ need to be adjusted to? Thanks for your help. @MichaelButscher
@Thingamabobs do you mean passing ‘i’ as an argument, then using it to change the specific element? If so, I’ll make sure to give it a go. Thanks! 🙂
Yes, especially you can use “i” as index for your list, in case you need to address the button.
Show 2 more comments