0

I'm creating multiple radiobuttons in a loop and assigning a function with one argument to them by lambda(These functions are also created using loops and dictionary), but when I press on on of the radiobuttons I get this error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/home/shirin/anaconda3/lib/python3.8/tkinter/__init__.py", line 1892, in __call__
    return self.func(*args)
  File "/tmp/ipykernel_7981/822586079.py", line 99, in <lambda>
    lst_r["r{0}".format(f+j)] = Radiobutton(text = algorithms[f+j], var = v, value = f+j, height=2, width=30, indicator = 0, command = lambda: d['use_algo'+str(f+j)](algorithms[f+j]))
KeyError: 'use_algo35'

For the algorithm files I created 4 .py files containing the following code:

def print_array(array):
    array2 = []
    for i in array:
        array2.append(i) 
        print array2
array = arr
print_array(array)

And here is a minimal code like mine; Running this code it returns KeyError: 'use_algo5':

from tkinter import *

root = Tk()
row_num = 0
font = ('Verdana', 10)

algorithms = ['algorithm1','algorithm2','algorithm3','algorithm4']

def enter():
    try:
        class entries:
            def __init__(self, root):
                self.variables = []
                n = 4
                for i in range(n):
                    self.variables.append(StringVar())

                self.labels = []
                self.entries = []
                c, d, e = 0,0,0
                
                for ii in range(int(n/4)):
                    for jj in range(4):
                        num = c+(jj+1)
                        self.labels.append(Label(root , text = num))
                        self.labels[-1].grid(padx=0, pady=0, row=ii+d+1, column=jj)
                        self.entries.append(Entry(root, font = font, textvariable =self.variables[c+(jj)], width = 30))
                        self.entries[-1].grid(padx=0, pady=0, row=ii+d+2, column=jj)
                    d+=2   
                    c+=4
                    e = ii+1+d
        
                label_algo = Label(font = font, text = 'Choose an algorithm:')
                label_algo.grid(row = int(n/4)+e+2 , column = 0, padx = 29, pady = 15)
                row_num = int(n/4)+e+2
                
                def use_algo(algo_name):   ### radio button functions:
                    arr = []
                    for i in range(int(len(self.entries))):
                        arr.append(self.entries.get())
                    arr = exec(open("/home/shirin/Desktop/Python Project/Algorithms/" + algo_name + ".py").read())
                    label_output.configure(text = 'The array is {}'.format(arr))

                d = {f'use_algo{k}': partial(use_algo, algo_name=algorithms[k]) for k in range(int(len(algorithms)))}

                v = IntVar()
                lst_r = {}
                f = 0
                for i in range(int(len(algorithms)/2)):    ### making radio buttons:
                    for j in range(2):
                        lst_r["r{0}".format(f+j)] = Radiobutton(text = algorithms[f+j], var = v, value = f+j, height=2, width=30, indicator = 0, command = lambda: d['use_algo'+str(f+j)](algorithms[f+j]))
                        lst_r["r{0}".format(f+j)].grid(row=row_num+1+i, column=j)
                    f+=2

                label_output = Label(font = font)
                label_output.grid(row = row_num+1+int(len(algorithms)/4)+1 , column = 0, padx = 29, pady = 15) 
      
        T = entries(root)
        
    except:
        pass

label_num = Label(font = font, text = 'Press enter button')
label_num.grid(row = 0 , column = 0, padx = 30, pady = 15)
button_enter = Button(text = 'Enter', command = enter, width = 20)
button_enter.grid(row = 0 , column = 2, padx = 30)

root.mainloop()
ShirinJZ
  • 107
  • 2
  • 16
  • You're getting this error because the key `use_algo35` isn't in your dictionary. Hard to further troubleshoot it without the `algorithms` function – jezza_99 Nov 28 '21 at 22:31
  • @jezza_99 Yeah, but I debugged my code multiple times and couldn't understand why it returns 35! I also updated the code and added algorithms. – ShirinJZ Nov 28 '21 at 22:42
  • Any chance you can supply the txt file you are using? – jezza_99 Nov 28 '21 at 22:50
  • It's a 32-row text file, there is a name in each row, I think that's not the root of problem, since I reduced the length of algorithms and it still returns 35! – ShirinJZ Nov 28 '21 at 23:11
  • I'm sorry but I can't replicate your error using the code you've provided. Can you provide it as a [mre], that we can copy, paste and run to get the same error as you? – jezza_99 Nov 28 '21 at 23:30
  • 1
    @ShirinJZ `lambda: d['use_algo'+str(f+j)](algorithms[f+j]` this is not how lambda works, it will be overwritten in each iteration of your loop. You may find the solution by yourself, while reading [this](https://stackoverflow.com/questions/16501/what-is-a-lambda-function/62742314#62742314) – Thingamabobs Nov 29 '21 at 02:28
  • 1
    You have similar issue in [this](https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop) question. And it is usually use `partial()` directly in `command` option like `command=partial(use_algo, algorithms[f+j])`. – acw1668 Nov 29 '21 at 04:39
  • @jezza_99 I've added a minimal code like mine. – ShirinJZ Nov 29 '21 at 06:23
  • 1
    When the lambda is executed by clicking one of the radiobuttons, `f+j` is 5 because `f` is 4 and `j` is 1 after the for loop of creating those radiobuttons. As I said in my last comment, use `command=partial(use_algo, algorithms[f+j])` and then `d` is not necessary at all. Also the for loop inside `use_algo()` is not necessary. – acw1668 Nov 29 '21 at 07:36
  • @acw1668 Got it, thanks alot. – ShirinJZ Nov 29 '21 at 07:39
  • @acw1668 please post your comment as an answer, so I can accept it. :) – ShirinJZ Nov 29 '21 at 07:48

1 Answers1

1

When the lambda is executed by clicking one of the radiobuttons, f+j is 5 because f is 4 and j is 1 after the for loop of creating those radiobuttons.

Also it is usually use partial() directly in command option as below:

command=partial(use_algo, algorithms[f+j])

Then d is not necessary at all.

Note that the for loop inside use_algo() is not necessary because arr is overwritten by:

arr = exec(open("/home/shirin/Desktop/Python Project/Algorithms/" + algo_name + ".py").read())
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Actually, the loop is there cause I am going to get the values inserted in entries by the user and pass them as input to the algorithm. Also, the dictionary remained there from my past code. :) – ShirinJZ Nov 29 '21 at 08:16