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.
Related
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.
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.
I believe I have some fundamental misunderstanding of Python global variables and their scope, and I was hoping someone can educate me.
Say I have two Python files.
#"GlobalSet.py"
global myVar
myVar = True
print "myVar" in globals()
import GlobalCheck
and
#"GlobalCheck.py"
print "myVar" in globals()
Running "GlobalSet.py" surprisingly results in
True
False
Why isn't "myVar" in the global scope within "GlobalCheck"?
Global in Python means global to the current module. To share variables between modules you need to import them.
Note that the global keyword in your code is doing nothing at all, since myVar is already defined at module level. You would only need to use that keyword if you were modifying the value of myVar inside a function in that module.
The global is within the context of the module. In GlobalCheck.py, if you put
import GlobalSet
print GlobalSet.myVar
that will work. (globals() doesn't appear to work across modules.)
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.
I keep getting an unbound local error with the following code in python:
xml=[]
global currentTok
currentTok=0
def demand(s):
if tokenObjects[currentTok+1].category==s:
currentTok+=1
return tokenObjects[currentTok]
else:
raise Exception("Incorrect type")
def compileExpression():
xml.append("<expression>")
xml.append(compileTerm(currentTok))
print currentTok
while currentTok<len(tokenObjects) and tokenObjects[currentTok].symbol in op:
xml.append(tokenObjects[currentTok].printTok())
currentTok+=1
print currentTok
xml.append(compileTerm(currentTok))
xml.append("</expression>")
def compileTerm():
string="<term>"
category=tokenObjects[currentTok].category
if category=="integerConstant" or category=="stringConstant" or category=="identifier":
string+=tokenObjects[currentTok].printTok()
currentTok+=1
string+="</term>"
return string
compileExpression()
print xml
The following is the exact error that I get:
UnboundLocalError: local variable 'currentTok' referenced before assignment.
This makes no sense to me as I clearly initialize currentTok as one of the first lines of my code, and I even labeled it as global just to be safe and make sure it was within the scope of all my methods.
You need to put the line global currentTok into your function, not the main module.
currentTok=0
def demand(s):
global currentTok
if tokenObjects[currentTok+1].category==s:
# etc.
The global keyword tells your function that it needs to look for that variable in the global scope.
You need to declare it global inside the function definition, not at the global scope.
Otherwise, the Python interpreter sees it used inside the function, assumes it to be a local variable, and then complains when the first thing that you do is reference it, rather than assign to it.