0

I'm now running an error (first off I already know that using exec isn't the best option but I'd rather not get into that right now) about a variable being undefined when referencing it. Which I find very strange considering it was working perfectly fine when I was using exec(f'oneMileMark.append(entry{i}.get())') (it was already a float at this point) before I added the ability to use the standard time format (1:36).

for i in range(numOfRunners):
    if i%4 == 0: # used to distinguish between a runner's name and different times
        exec(f'time = entry{i}.get()') # gets the value of entry{i} and saves it as time
        minutes,seconds=time.split(':') # splits time into mins and secs
        newTime=float(minutes) + float(seconds)/60 # combines the minutes and hours into one bariable
        oneMileMark.append(newTime) # adds newTime to a list

Which gives the error:

Traceback (most recent call last):
  File "/Users/Me/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 91, in <module>
    app = Application(root)
  File "/Users/Me/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 12, in __init__
    self.get_runner_data()
  File "/Users/Me/Desktop/Computer Programming/Python 3.x/Assignments/Programming 2/8/9_15 Computing 5k Mile Splits/main.py", line 53, in get_runner_data
    hours,minutes=time.split(':')
NameError: name 'time' is not defined

1 Answers1

0

Based on your traceback and previous post, you are using exec within a method of a class like so:

class Foo:
    def bar(self):
        exec('x = "Hello World"')
        print(x)

When exec is executed within a function definition without a parameter for globals, any variables it creates is assigned to a new, temporary namespace, which cannot be accessed. Essentially, your time variable was made in an inner scope (which gets thrown away after exec finishes), and so you cannot access it outside of that scope.

>>> Foo().bar()
Traceback (most recent call last):
  ... 
  File "..\main.py", line 4, in bar
    print(x)
NameError: name 'x' is not defined

Why your previous exec() used to work before is because it only accessed oneMileMark and mutated the list with .append(), and didn't try to assign something new to the variable.

To solve this, you can use eval instead of exec so you can evaluate the expression while keeping your variable assignment remaining in the same scope:

for i in range(numOfRunners):
    if i%4 == 0:
        time_ = eval(f'entry{i}.get()')
        minutes,seconds=time_.split(':')
        ... 

Note: If you were to use exec in the module level (outside of function or class definitions), any variable assignments will work on the global namespace:

>>> exec('x = "Hello World"')
>>> x
'Hello World'
thegamecracks
  • 585
  • 2
  • 8