0

Right now I'm working on a project that will ask for a runner's name, 1 mile, 2 mile, and 5 miles times and generate data based off that. The requirement is to have enough entries for 7 runners but I thought I'd add the ability to add any number of runners by using exec(). However, when trying to read data from the variables defined within them, I get a NameError: name 'entry2' is not defined but not for entry0 and entry1, so I was wondering if anyone could help me out on these. In case it helps, I don't necessarily need to use exec() to create them but it was what I knew could define variables and later read from them.

All code:

from UsefulFunctions import setup_screen, clear_window # just some of my functions, pretty obvious what they do
from tkinter import *

class Application(Frame):
    def __init__(self, master):
        Frame.__init__(self,master)
        self.grid()
        self.create_widgets()
        
    def create_widgets(self):
        Label(self,text='Enter how many runners you\' entering times for:').grid()
        numOfRunners=Entry(self);numOfRunners.grid()
        var = IntVar()
        test = Button(self, text = "Submit", command = lambda: var.set(1)); test.grid()
        while True:
            try:
                test.wait_variable(var)
                numOfRunners=int(numOfRunners.get())
                break
            except ValueError:
                Label(self,text='Make sure that you use a number like \'4\', not \'four\'!').grid(row=3)
        clear_window(self)
        
        Label(self,text='Input').grid(row=0,column=0,sticky=W)
        for i in range(numOfRunners):
            columnNum=0
            Label(self,text='Runner Name').grid(row=(i*2)+1,column=0,sticky=W)
            Label(self,text='1 Mile Mark Time').grid(row=(i*2)+1,column=1,sticky=W)
            Label(self,text='2 Mile Mark Time').grid(row=(i*2)+1,column=2,sticky=W)
            Label(self,text='5k Time').grid(row=(i*2)+1,column=3,sticky=W)
            for col in range(4):
                exec('entry%s=Entry(self);entry%s.grid(row=%s,column=%s)' % (str(i),str(i),str((i*2)+2),str(col)))
        runnerNames=[]
        oneMile=[]
        twoMile=[]
        fiveK=[]
        var = IntVar()
        submitButton = Button(self, text = "Submit", command = lambda: var.set(1)); submitButton.grid(sticky=W)
        submitButton.wait_variable(var)
        
        for i in range(numOfRunners*4):
            exec("print('entry%s.get() = ' + entry%s.get())" % (i,i))
        
        self.calculate(runnerNames,oneMile,twoMile,fiveK)
        
    def calculate(self,runnerNames,oneMile,twoMile,fiveK):
        print(runnerNames)
        print(oneMile)
        print(twoMile)
        print(fiveK)
        
root =Tk()
root.title("AT Pace Check Times")
setup_screen(root, 800, 400)
app = Application(root)
root.mainloop()

Here's the full error log:

Traceback (most recent call last):
  File "/Users/122224/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 70, in <module>
    app = Application(root)
  File "/Users/122224/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 12, in __init__
    self.create_widgets()
  File "/Users/122224/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 48, in create_widgets
    exec("print('entry%s.get() = ' + entry%s.get())" % (i,i))
  File "/Users/122224/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 1, in <module>
    try:
NameError: name 'entry2' is not defined
  • Use f string for better understanding, rather than placeholders – Delrius Euphoria Sep 17 '20 at 15:10
  • so use `exec("print('entry{i}.get() = ' + entry{i}.get())".format(i))` instead? Because that's raising `KeyError: 'i'`, but I wouldn't be surprised if I did something wrong. – DartRuffian Sep 17 '20 at 15:17
  • `exec(f"print(....).....` you forgot the `f` but i dont think it will fix the error, its just cleaner to look into – Delrius Euphoria Sep 17 '20 at 15:18
  • You _really_ shouldn't use `exec` to create dynamic variables. It makes the code very hard to understand and very hard to debug and maintain over time. Store your widgets in a dictionary instead. – Bryan Oakley Sep 17 '20 at 15:18
  • @BryanOakley would there be a way to create `x` rows of labels and entries other than `exec`? – DartRuffian Sep 17 '20 at 15:24
  • yes, just add them to a dictionary. Here's one example: https://stackoverflow.com/a/49453736/7432 – Bryan Oakley Sep 17 '20 at 15:26
  • So how exactly would this work when using entries? Because (at least with the way I'm doing it right now) I'm defining the tkinter entries using `exec()`, would I have to pre-define them using `IntVar()`/`StringVar()` and then use them as textvariables in the entries? – DartRuffian Sep 17 '20 at 15:38
  • @BryanOakley because I just don't see a way to use them with entries then than pre-defining them – DartRuffian Sep 17 '20 at 15:55
  • There's nothing special about entries; `entries={}; entries["entry1"] = Entry(...); entries["entry2"] = Entry(...)`, etc. – Bryan Oakley Sep 17 '20 at 17:20

1 Answers1

0

In case anyone cares it was because I was using an older variable i and didn't either set it to 0 or use another variable.