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.
Related
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.
This question already has answers here:
Short description of the scoping rules?
(9 answers)
Using global variables in a function
(25 answers)
Closed 5 years ago.
I have a question regarding globals() in python
My sample code
b=9
def a1():
'kkk'
a1()
print globals()
I got output b as global
Since b is global, I am expecting I can modify it anywhere
So I modified my code to
b=9
def a1():
'kkk'
b=100
a1()
print globals()
still my globals() says b as 100. Why b inside the function is taken as local value while my globals() says its global?
Note: If I add keyword global b inside the function, it get convert to global.
My question is why b was not getting modified inside the function while globals() declare b as global ?
Refer Python docs for more information. Copying the text in case URL doesn't work
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.
inside a function, unless you use the keyword global, it is not global variable that is modified. instead,a local variable is created and is destroyed as soon as it is out of scope
As your code b is a local variable in a1(), to use global variable, you should first say that to python and then use it, as follows:
b=9
def a1():
'kkk'
global b
b=100
a1()
print globals()
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.
This question already has answers here:
Using global variables in a function
(25 answers)
Closed 8 years ago.
Think I'm going nuts here.
url_request = 0
def somefunction():
url_request+=1
if __name__ =='__main__':
somefunction()
Gives me the UnboundLocalError. What important concept am I missing here?
You are assigning to a global variable, which means you need to mark it as a global:
def somefunction():
global url_request
url_request+=1
When you assign to a variable in a local scope, it is assumed to be a local variable unless you use a global statement to tell python otherwise first.
For Python 2.7 we have to types of variables: global, local. Each function create it's own local scope for variables.
From local scope you can read without any restrictions. You can also call global object methods, so you can modify variable from global. But you can't reassign value.
Look at this code:
requests = [1,2,3]
def modify():
requests.append(4)
def redeclare():
requests = [10,20,30]
modify()
print requests
# will give you [1,2,3,4]
redeclare()
print requests
# will give you [1,2,3,4]
What's going on? You can't reassign requests variable from local scope, so interpreter create for you other variable - in local scope for redeclare call context.
Regarding to your code... Firstly, you try to reassign variable from global scope. Why? url_request is int, int is immutable, so operation url_request+=1 doesn't change value, it should reassign new value to variable name. Secondly, you don't specify global identify for this variable. So only one option for interpreter - to assume url_request as local variable. But... You didn't declare it's value anywhere....
UnboundLocalError means that you try to perform operations with variable value without declaring it before. Hope this will help you to understand more about Python variables/names/scopes.
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.