Python Forum
[variable] is not defined error arises despite variable being defined - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: [variable] is not defined error arises despite variable being defined (/thread-36837.html)



[variable] is not defined error arises despite variable being defined - TheTypicalDoge - Apr-05-2022

I've come across an error that I'm not sure how to fix. I keep getting an error that 'currentCalcInput' isn't defined even though it's defined before it's used. I'm not sure what's happening here.
To confirm, currentCalcInput is only ever used in that function and no where else. I've also copied this snippet into another file and it works just fine, so I'm assuming it's the context in which its used in. I'm not really sure, so I'm open to help.

        currentCalcInput = ""

        def buttonPress(key):
            global currentCalcInput
            currentCalcInput += key
Output:
NameError: name 'currentCalcInput' is not defined
[Edit] Here is the full code that doesn't work:
from tkinter import *

class Gui:

    def __init__(self, root):
        currentCalcInput = ""

        def buttonPress(key):
            global currentCalcInput
            currentCalcInput += key

        def generateButtons():
            posOffset = (0, 0)
            buttonSizes = (6, 3)
            buttonNames = ["1", "4", "7", "Clear", "2", "5", "8", "0", "3", "6", "9", "=", "+", "-", "*", "/"]
            buttonNamesIndex = 0
            for x in range(4):
                for y in range(4):
                    Button(root, text=buttonNames[buttonNamesIndex], width=buttonSizes[0], height=buttonSizes[1],
                           command=lambda buttonId=buttonNames[buttonNamesIndex]: buttonPress(buttonId)). \
                        grid(column=x + posOffset[0], row=y + posOffset[1])
                    buttonNamesIndex += 1

        generateButtons()

        root.mainloop()


guiRoot = Gui(Tk())



RE: [variable] is not defined error arises despite variable being defined - bowlofred - Apr-05-2022

I think you'll have to show the code of the one where it doesn't work.

You could set a breakpoint at the part where you think it is set and see if you reach that point before the error is generated.


RE: [variable] is not defined error arises despite variable being defined - TheTypicalDoge - Apr-05-2022

(Apr-05-2022, 03:08 AM)bowlofred Wrote: I think you'll have to show the code of the one where it doesn't work.

You could set a breakpoint at the part where you think it is set and see if you reach that point before the error is generated.

I've edited the post to include the code that wasn't working.


RE: [variable] is not defined error arises despite variable being defined - menator01 - Apr-05-2022

Take a look at global scope, class scope and function scope. That's where your trouble is happening.


RE: [variable] is not defined error arises despite variable being defined - deanhystad - Apr-05-2022

There is no currentCalcInput in the global scope. There is an is Gui.__init__(), but global looks for variables in the global (module) scope, not the enclosed scope. You should either make currentCalcInput a mutable type, or pass it as an argument to the function. Here I make it mutable by putting the string in a list. buttonPress() changes the value in the list. It does not assign a new value to currentCalcInput.
from tkinter import *
 
class Gui(Tk):
 
    def __init__(self):
        super().__init__()
        currentCalcInput = [""]
 
        def buttonPress(key):
            currentCalcInput[0] += key
            print(currentCalcInput)
 
        def generateButtons():
            posOffset = (0, 0)
            buttonSizes = (6, 3)
            buttonNames = ["1", "4", "7", "Clear", "2", "5", "8", "0", "3", "6", "9", "=", "+", "-", "*", "/"]
            buttonNamesIndex = 0
            for x in range(4):
                for y in range(4):
                    Button(self, text=buttonNames[buttonNamesIndex], width=buttonSizes[0], height=buttonSizes[1],
                           command=lambda buttonId=buttonNames[buttonNamesIndex]: buttonPress(buttonId)). \
                        grid(column=x + posOffset[0], row=y + posOffset[1])
                    buttonNamesIndex += 1
 
        generateButtons()
        self.mainloop()

Gui()
I don't like this design pattern at all. You are using an obscure and confusing (to me) enclosing scope behavior where you should be using an instance variable and method.
import tkinter as tk
 
class Gui(tk.Tk):
    def __init__(self):
        super().__init__()
        self.currentCalcInput = ""  # <- Instance variable
        buttons = ("1", "4", "7", "Clear", "2", "5", "8", "0", "3", "6", "9", "=", "+", "-", "*", "/")
        for index, btn in enumerate(buttons):
            tk.Button(self, text=btn, width=6, height=3, command=lambda arg=btn: self.buttonPress(arg)). \
                grid(row=index % 4, column=index // 4)

    def buttonPress(self, key):
        self.currentCalcInput += key  # <- Instance variable
        print(self.currentCalcInput)

Gui().mainloop()