UnboundLocalError local variable referenced before assignment - python

When I run this code, I get an error that says UnboundLocalError: local variable 'rootent' referenced before assignment.
class calculator():
def __init__(self):
def options():
fetch=float(rootent.get()) #Location of error
if fetch=='1':
def IEntry():
fetch=float(rootent.get())
fetch1=float(rootent1.get())
answer=fetch,'+',fetch1,'=',fetch1+fetch2
ansLabel=Label(root,text=answer).pack()
root=Tk()
root.title('Addition')
root.geometry('450x450+200+200')
rootlabel=Label(root,text='Enter first number').pack()
rootent=Entry()
rootent.pack()
rootlabel1=Label(root,text='Enter second number').pack()
rootent1=Entry()
rootent1.pack()
return
root=Tk()
root.title('Calculator Menu')
root.geometry('450x450+200+200')
rootlabel=Label(root,text='1.Addition').pack()
rootlabel1=Label(root,text='2.Subtraction').pack()
rootlabel2=Label(root,text='3.Multiplication').pack()
rootlabel3=Label(root,text='4.Division').pack()
rootent=Entry(root) #This is what i am trying to input into 'def options()'
rootent.pack()
rootbutton=Button(root,text='Enter option',command=options).pack()
I have tried making rootent global in the function, and I've tried passing it as a para with no luck.
What is wrong, and how do I fix it?

The problem is that python scoping rules are a bit strange. If a function has an assignment to a variable, that variable is assumed local to the function and python won't look in enclosing scopes. In your case, the offending line is rootent=Entry(). your call to rootent.get() is trying to access this rootent variable before it has been assigned. Since you are in python 3.x you can use the nonlocal declaration to make python access the outer scope. Just put nonlocal rootent at the beginning of options() and I think it will work correctly.
There is more discussion of the use of the nonlocal operator here: Python nonlocal statement
Basically, global tells python that the variable name in question resides at the module (file) level. nonlocal tells python to search enclosing scopes for the named variable and use that version, which is more like the behavior you get 'by default' in other languages where you have to explicitly declare all variables.

You are trying to get something from a variable that has not been previously declared. Where is the rootent variable declared in your code?. You need to show us that. It is hard to guess what the type of rootent is.

Thanks for the help, it's now fixed, added nonlocal and changed float(rootent.get()) to rootent.get() and it seemed to fix everything.

Related

Why Python "global" statement is always evaluated, even under conditional statement that is not met?

I don't know how to explain the case, just try for yourself:
x = 7
def f():
if False:
global x
print("global")
x += 1
f()
print(x)
In my opinion, the above code should result in "UnboundLocalError: local variable 'x' referenced before assignment", but instead it not only works, but it changes the global variable 'x'.
A function gets a local namespace every time it is called. Python needs a way to know which variables are defined in that namespace or a containing namespace. Instead of requiring that all local variables be declared local, python's rule is that any variable that is assigned in a function is local to that function. It figures this out at compile time.
The global keyword does the opposite. It tells python that in this single function, assignment to the "global" variable is really an assignment in the enclosing namespace. Like local variables, this is figured out when the function is compiled. Because of compilation issues, python requires that the global be declared before the first reference to the variable. This is a compile thing, not a runtime thing, so its okay for it to be in a block that isn't ever really run.

Why does python behave this way with variables? [duplicate]

This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 5 months ago.
I have been trying to understand why python behaves this way, in the block of code below. I have done my research but couldn't find a good answer so I came here to see if anyone can point me in the right direction or provide a good clarification.
I understand that it has to do with some old ALGOL principle, but I don't fully understand it.
var = 5
def func1():
print(var)
func1()
def func2():
var = 8
print(var)
func2()
def func3():
print(var)
var = 8
func3()
The output of this code is as follows:
5
8
UnboundLocalError: local variable 'var' referenced before assignment
I understand why we get the outputs '5' and '8'. But with 'func3()', I was expecting an output of '5'. As it seems, the interpreter thinks that I want to print the local 'var' in the function instead of the global 'var'. So it throws this error.
Or maybe if a variable is defined somewhere inside of the function, then the function will default to the local variable, instead of a global one with the same name.
But why exactly does python behave this way ? I am not complaining, I am just trying to understand something...
How could I use a predefined global variable in a function, then define a local variable with the same name inside of the same function, without changing the value of the global variable ? ( in python of course )
Thanks in advance to everyone here. You are amazing people ! :)
Edit_1: Thanks every one for the great answers. I totally understand that it is a bad and unpractical idea to use a predefined global variable in a function, then define a local variable with the same name inside of the same function. I was just thinking about it from a theoretical perspective, because I saw it in a college lecture. XD
I can't find a single use case, in which it would be optimal to do that either !
Edit_2: I already read the PEP8 and I know that being explicit is better than being implicit. :)
It's true. Otherwise the code will be confusing and lead to bugs.
That question was just about some useless and impractical college theory that I was trying to understand.
Edit_3:
Now I fully understand why it happens and what is going on here. Thanks to Randall Valenciano for providing this link to a blog that explains it very well.
What happens is that the function is interpreted as a whole, and not line by line. So when the function is being interpreted, the variable declarations of any defined variables, are moved to the top of the function. So when we are printing 'var', the function is using the locally declared variable that doesn't have any value assigned to it yet, and then the interpreter complains about it and throws and error.
Thanks to all of you again ! :)
You have been of great help to me ! Now I finally understand what is going on there under the hood.
Your var is defined as a global variable. In each function when you're only reading the var you're accessing the global var, but the moment there's an assigned value to var somewhere in the function, python treats every var within the function as a local variable. Thus why your last function failed, because print(var) (the local varaible) was called before var = 8 was assigned.
You can read up a bit about more in these threads:
How bad is shadowing names defined in outer scopes?
Python nonlocal statement
The best thing to do is be explicit about your code so it's no longer confusing if you're trying to reference a local, nonlocal or global variable.
In this case, assuming your intention is to keep using the global var, do this:
var = 5
def func1():
print(var)
func1()
def func2():
global var
var = 8
print(var)
func2()
def func3():
global var
print(var)
var = 8 # technically this is not necessary any more var = 8 was already assigned when func2() is called
func3()
The output is thus:
5
8
8
Edit: Thanks to juanpa.arrivillaga's comment - I missed your original question.
How could I use a predefined global variable in a function, then
define a local variable with the same name inside of the same
function, without changing the value of the global variable ? ( in
python of course )
The short answer is - define the local var first like you did in func2() and you're good. The longer answer though is - why would you want to do that? It creates confusion and becomes a headache to track which is when you have variables of the same name in different scope. A better approach would be name your local var to be local_var or something so it's distinctly different and easily traced.
Here's a rule for Python Scope Resolution from this answer
LEGB Rule.
L, Local — Names assigned in any way within a function (def or lambda)), and not declared global in that function.
E, Enclosing-function locals — Name in the local scope of any and all statically enclosing functions (def or lambda), from inner to outer.
G, Global (module) — Names assigned at the top-level of a module file, or by executing a global statement in a def within the file.
B, Built-in (Python) — Names preassigned in the built-in names module : open,range,SyntaxError,...
So basically in your question, the scope resolution is "from inside out" and since you aren't using the global keyword, the interpreter doesn't know to look outside the local function scope to find that variable var. All the interpreter sees is that you are using a variable before declaring and defining it, thus throwing the error. Global variables are often dangerous, and so Python wants to make sure you know you want to use a global variable by forcing you to be explicit about it.
See this other answer for an explanation of the global keyword
Hope it helps.

Local and global references with UnboundLocalError

I don't quite understand why the code
def f():
print(s)
s = "foo"
f()
runs perfectly fine but
def f():
print(s)
s = "bar"
s = "foo"
f()
gives me UnboundLocalError. I know that I can fix this by declaring s as a global variable inside the function or by simply passing s an an argument into the function.
Still I don't understand how python seemingly knows whether or not s is referenced inside the function before the line has been executed? Does python make some sort of list of all local variable references when the function is read into the global frame?
Other answers have focused on the practical aspects of this but have not actually answered the question you asked.
Yes, the Python compiler tracks which variables are assigned when it is compiling a code block (such as in a def). If a name is assigned to in a block, the compiler marks it as local.Take a look at function.__code__.co_varnames to see which variables the compiler has identified.
The nonlocal and global statements can override this.
Yes, Python will look-ahead to recover all variables declared in the local scope. These will then overshadow global variables.
So in your code:
def f():
print(s)
s = "foo"
f()
Python did not find s in the local scope, so it tries to recover it from the global scope and finds "foo".
Now in the other case the following happens:
def f():
print(s)
s = "bar
s = "foo"
f()
Python knows that s is a local variable because it did a look-ahead before runtime, but at runtime it was not assigned yet so it raised and exception.
Note that Python will even let you reference variables that have not been declared anywhere. If you do:
def foo():
return x
f()
You will get a NameError, because Python, when not finding, x as a local variable will just remember that at runtime it should look for a global variable named x and then fail if it does not exist.
So UnboundLocalError means that the variable may eventually be declared in scope but has not been yet. On the other hand NameError means that the variable will never be declared in the local scope, so Python tried to find it in the global scope, but it did not exist.

Python UnboundLocalError Embedded def

This usually works; however, it's not this time:
def fn(text):
def fn2():
print text
fn2()
How can I fix this?
Thanks.
Edit: I don't want to pass in text.
I would suggest reading this page: http://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/
So where does the exception come from? Quoting the FAQ:
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope.

python global variable trouble

I am having troubles using global variables in python...
In my program, i have declared 2 global variables,
global SYNC_DATA and
global SYNC_TOTAL_SIZE
Now in one of my functions, I am able to use the global variable SYNC_DATA without declaring it as global again in the function; however , I am not able to use the other global variable SYNC_TOTAL_SIZE in the same way. I have to declare the latter as global in the function again to use it. I get this error if i use it without declaring as global in the function - "UnboundLocalError: local variable 'SYNC_TOTAL_SIZE' referenced before assignment"
Why is it so that sometimes I can access global variables without declaring them as global in functions and sometimes not?
And why Is it that we have to again declare it as global in the function when it is already declared once in the beginning... Why doesn`t the function just check the variable in the global namespace if it does not find it in its namespace directly?
Assuming SYNC_TOTAL_SIZE is not declared as local variable. It depends on what operations you are performing on global variables, for just reading the global variable there is no need to declare it as global, but if you are modifying the value of global variable you have to declare it with global.
Because SYNC_TOTAL_SIZE is probably used somewhere else in that code as non-global, which makes Python find it and think it isn't global. Another reason may be that you just read it in some function and so it doesn't need a global declaration (see this question for more details). For an exact diagnosis, post a minimal code snippet that demonstrates your problem.
The advice is to always say global when you mean it.

Categories

Resources