How do I get the modify_attr()
function (below) not to capture/update the value of b in the following for loop? (simplified version, occurring within a mainloop()
):
for b in range(x):
button = tk.Button(button_frame, text="<", command=lambda: current_instance.modify_attr(b, -1))
button.place(x=110, y=80 + 18 * b)
button = tk.Button(button_frame, text=">", command=lambda: current_instance.modify_attr(b, 1))
button.place(x=120, y=80 + 18 * b)
The goal is to generate two columns of buttons and to bind each button pair to a (somewhat complicated) pair of functions (conditional reduce_by_one / increase_by_one functions).
- x = the number of button pairs I need generated
- current_instance = a class instance
- modify_attr = a class method accepting two arguments (well I guess three if we include self)
My understanding (based on this and other things I've read over the past few) is that this issue is a common one. At its heart, the problem is that all values of b with respect to modify_attr() wind up equal to len(x)
(rather than the value of b at the moment I intend to bind that command to the button). The result is a series of buttons that are positioned properly (via the b value(s) in button.place
) but all pointing to the last element in the list they're supposed to be modifying.
I previously encountered this exact problem and was able to work around it using a helper function. But for some reason I am unable to apply that solution here (again, simplified for clarity):
for b in range(len(the_list)):
def helper_lambda(c):
return lambda event: refresh_frame(the_list[c])
window.bind(b + 1, helper_lambda(b))
Does that make sense? Exact same issue, helper_lamdba works like a charm. Now, in this case, I'm binding a hotkey rather than a button command, but I simply can't get my head around why it would work differently. Because fundamentally the problem is with the for loop, not the functions within. But when I implement a helper function in my button loop it fails like a not-a-charm.
Here is my failed attempt to apply that helper strategy:
for b in range(x):
def helper_lambda(c, modifier):
return lambda event: current_instance.modify_attr(c, modifier)
button = tk.Button(button_frame, text="<", command=lambda: helper_lambda(b, -1))
button.place(x=110, y=80 + 18 * b)
button = tk.Button(button_frame, text=">", command=lambda: helper_lambda(b, 1))
button.place(x=120, y=80 + 18 * b)
What am I doing wrong? Also, why does it behave this way? Is anyone using incrementor values outside of for loops?!