I have this code:
def r():
i += 1
return i
def f():
return x*a
i = 0
a=2
x=3
print f()
print r()
I get this error for r(), but not for f():
~$ python ~/dev/python/inf1100/test.py
6
Traceback (most recent call last):
File "/home/marius/dev/python/inf1100/test.py", line 18, in <module>
print r()
File "/home/marius/dev/python/inf1100/test.py", line 2, in r
i += 1
UnboundLocalError: local variable 'i' referenced before assignment
Why can f() use variables defined outside of the function, whilst r() cannot?
That's because r reassigns the global variable i. f on the other hand just uses it. Remember that i += 1 is the same as i = i + 1.
Unless you explicitly tell it otherwise, Python treats all variables used within a function as being local. Furthermore, since there is no variable i defined within the local scope of r, it throws the error.
If you want to reassign a global variable within a function, you have to put:
global var
at the top of your function to explicitly declare var to be global.
So, to make r work, it should be rewritten to this:
def r():
global i
i += 1
return i
I'd like to point out that most of the time, this:
x = 1
def f():
global x
x += 1
f()
is bad practice, and you want to use parameters instead:
x = 1
def f(a_number):
return a_number + 1
x = f(x)
Also, here:
def r():
global i
i += 1
return i
return i is redundant, the variable is increased by the calling of the function.
Also this part of the Python FAQ is relevant and useful.
This piece:
def r():
i += 1
return i
not only uses global variables, but also tries to modify them (or more accurately: assign different value to global variable i).
To make it work, you can just declare this variable as global:
def r():
global i
i += 1
return i
In r you are shadowing your global i. Since it is not assigned before you attempt to add to it, you get an error.
A possible solution is to use global i in the r function like so
def r():
global i
i += 1
return i
If you assign into a variable, python will consider the variable local and won't bother looking for a global variable of the same name. Use global as suggested in other answers.
Related
I'm confused on the difference between local variables and global variables. I know that global variables are declared outside a function while local is declared in a function. However, I'm wondering if it is as so:
def func(l):
a = 0
n = len(l)
w = l[0]
while...
My question is, in the function i wrote as an example, i know that a is a local variable but what about the other two? are they local variables too?
l is a location variable that you passed into the function, and so is w since w is a "copy" of l[0]
To have a global variable you need to declare the variable as global using the global keyword.
x = 1
y = 2
def func(l):
global x
x = 4
l = 5
print("x is {0}, y is {1}".format(x,l))
func(y)
print("x is {0}, y is {1}".format(x,y))
Returns:
x is 4, y is 5
x is 4, y is 2
Notice how x is now changed but y isn't?
Note that lists are special because you don't need to declare the global keyword to append or remove from them:
x = []
def func():
x.append(3)
print("x is {0}".format(x))
func()
print("x is {0}".format(x))
Returns:
x is [3]
x is [3]
But references to lists are not global because they are a 'copy' of it :
x = [3]
y = 1
def func():
y = x[0]
print("y is {0}".format(y))
func()
print("y is {0}".format(y))
Returns:
y is 3
y is 1
Also Reassigning the variable that was a list is not global:
x = [3]
def func():
x = [2]
print("x is {0}".format(x))
func()
print("x is {0}".format(x))
Returns:
x is [2]
x is [3]
Also note that there are always a better way to do something than to declare global variables, because as your code scales it will get messier.
All those variables are assigned values and that automatically declares them in the local scope. So they are local variables.
Even if they had been declared outside in the global scope, they would still be local.
Unless you used the global keyword which tells the interpreter that the current scope refers to a previously declared global or creates a new one in the global context if none with the same name exists.
def func(l):
global n # n is declared in the global scope
a = 0
n = len(l)
w = l[0]
while...
func()
print(n)
All the variables in your function are local, usable by that function only. Global variables are usable by all functions in the class. In your function
def func(l):
a = 0
n = len(l)
w = l[0]
while...
>>>a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
a, n, w, and l are not usable outside of the func scope. If you did something like this...
a = 0
def func(l):
n = len(l)
w = l[0]
while...
>>>a
0
I just happened to come across this read which provides you with a lot of detail on variable declaration and scope.
[Python Doc the rule for local and global variables]:
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. illustrate this with your example:
Use your example to illustrate, all variables declared inside the func are local variables. and even values declared outside of the function. like variable x it has no parent function but it is still actually NOT a global variable. x just get commits to memory before the func gets called
x = 5 #actually local
def func(l):
a = 0
n = len(l)
w = l[0]
print(x) # x is local we call call it, use it to iterate but thats is pretty much it
if we try to modify the local variable x you would get an error:
x = 5
def func(l):
a = 0
n = len(l)
w = l[0]
x = x + 1 # can't do this because we are referning a variable before the funtion scope. and `x` is not global
UnboundLocalError: local variable 'x' referenced before assignment
but now if we define x as global then we can freely modify it as Python know anywhere when we call x is references to the same variable and thus the same memory address
x = 5
def func():
global x
x = x + 1
func()
print(x)
it prints out : 6 for the value of x
Hope through this example you see that global variable can be accessed anywhere in the program. Whereas local variable can only be accessed within its function scope. Also, remember that even though global variables can be accessed locally, it cannot be modified locally inherently.
Local Variable : When we declare a variable inside a function, it becomes a local variable.
global variable : When we declare a variable outside a function , it becomes a global variable.
A python program understand difference local vs global variable
#same name for local and global variable.
a = 1 #this is global variable
def my_function():
a = 2 #this is local variable
print("a= ", a) #display local var
my_function()
print("a = ", a) #display global var.
This program to access global variable
a = 1 #This is global var
def my_function():
global a #This is global var.
print("global a= ", a) #display new value
a = 2 #modify global var value
print("modify a = ", a) #display a new value
my_function()
print("global a= ", a) #display modified value
My main() function is:
def main():
...
def _help():
...
1 a += somelist
2 a.append(something)
a=[]
_help()
What's weird is that line 2 works perfectly fine, but line 1 throws an UnboundLocalError: Local variable 'a' referenced before assignment.
Even when I declare a as a global variable at the top of either main or _help, it still doesn't work. Why is this?
Both of these lines are editing the same variable which makes me think either both or neither of them should work. How do I get line 1 to work?
Whenever you use <variable> = <something> in Python, Python automatically assumes it is a local variable, unless specifically told otherwise.
For example:
a = 1
def f():
if False:
a = 0
print(a) # UnboundLocalError
f()
In this case, += works as assignment as well, but .append does not assign to a, but calls a method.
This is fixed by placing a nonlocal a in your function, so it can assign to the a outside of its scope:
def main():
...
def _help():
nonlocal a
a += somelist # Works!
But in this case, you can just do a.extend(somelist).
This question already has answers here:
Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope?
(9 answers)
Closed 6 months ago.
I have code like this (simplified):
def outer():
ctr = 0
def inner():
ctr += 1
inner()
But ctr causes an error:
Traceback (most recent call last):
File "foo.py", line 9, in <module>
outer()
File "foo.py", line 7, in outer
inner()
File "foo.py", line 5, in inner
ctr += 1
UnboundLocalError: local variable 'ctr' referenced before assignment
How can I fix this? I thought nested scopes would have allowed me to do this. I've tried with 'global', but it still doesn't work.
If you're using Python 3, you can use the nonlocal statement to enable rebinding of a nonlocal name:
def outer():
ctr = 0
def inner():
nonlocal ctr
ctr += 1
inner()
If you're using Python 2, which doesn't have nonlocal, you need to perform your incrementing without barename rebinding (by keeping the counter as an item or attribute of some barename, not as a barename itself). For example:
...
ctr = [0]
def inner():
ctr[0] += 1
...
and of course use ctr[0] wherever you're using bare ctr now elsewhere.
The Explanation
Whenever a value is assigned to a variable inside a function, python considers that variable a local variable of that function. (It doesn't even matter if the assignment is executed or not - as long as an assignment exists in a function, the variable being assigned to will be considered a local variable of that function.) Since the statement ctr += 1 includes an assignment to ctr, python thinks that ctr is local to the inner function. Consequently, it never even tries to look at the value of the ctr variable that's been defined in outer. What python sees is essentially this:
def inner():
ctr = ctr + 1
And I think we can all agree that this code would cause an error, since ctr is being accessed before it has been defined.
(See also the docs or this question for more details about how python decides the scope of a variable.)
The Solution (in python 3)
Python 3 has introduced the nonlocal statement, which works much like the global statement, but lets us access variables of the surrounding function (rather than global variables). Simply add nonlocal ctr at the top of the innerfunction and the problem will go away:
def outer():
ctr = 0
def inner():
nonlocal ctr
ctr += 1
inner()
The Workaround (in python 2)
Since the nonlocal statement doesn't exist in python 2, we have to be crafty. There are two easy workarounds:
Removing all assignments to ctr
Since python only considers ctr a local variable because there's an assignment to that variable, the problem will go away if we remove all assignments to the name ctr. But how can we change the value of the variable without assigning to it? Easy: We wrap the variable in a mutable object, like a list. Then we can modify that list without ever assigning a value to the name ctr:
def outer():
ctr = [0]
def inner():
ctr[0] += 1
inner()
Passing ctr as an argument to inner
def outer():
ctr = 0
def inner(ctr):
ctr += 1
return ctr
ctr = inner(ctr)
How about declaring ctr outside of outer (i.e. in the global scope), or any other class/function? This will make the variable accessible and writable.
How do I make code like the following work? I want to reference a variable, for assignment, in the enclosing function scope.
def outer():
x = 0
def inner():
x += 1
inner()
The code as written gives an UnboundLocalError. I understand why I get this error, I just don't know how I indicate that x comes from the wrapping scope.
You can do:
def outer():
x = [0]
def inner():
x[0] += 1
inner()
You can't rebind a non-local, but you can mutate it.
You cannot do what you ask in a clean way. There is nothing analagous to the global statement that can help you. You'll want to code it like this:
def outer():
x = 0
def inner(x):
return x + 1
x = inner(x)
This has the added advantage of making it explicitly clear as to how data passes into, and out of, the function.
Perhaps you will need to replace x with an object whose state can be mutated.
How do global variables work in Python? I know global variables are evil, I'm just experimenting.
This does not work in python:
G = None
def foo():
if G is None:
G = 1
foo()
I get an error:
UnboundLocalError: local variable 'G' referenced before assignment
What am I doing wrong?
You need the global statement:
def foo():
global G
if G is None:
G = 1
In Python, variables that you assign to become local variables by default. You need to use global to declare them as global variables. On the other hand, variables that you refer to but do not assign to do not automatically become local variables. These variables refer to the closest variable in an enclosing scope.
Python 3.x introduces the nonlocal statement which is analogous to global, but binds the variable to its nearest enclosing scope. For example:
def foo():
x = 5
def bar():
nonlocal x
x = x * 2
bar()
return x
This function returns 10 when called.
You need to declare G as global, but as for why: whenever you refer to a variable inside a function, if you set the variable anywhere in that function, Python assumes that it's a local variable. So if a local variable by that name doesn't exist at that point in the code, you'll get the UnboundLocalError. If you actually meant to refer to a global variable, as in your question, you need the global keyword to tell Python that's what you meant.
If you don't assign to the variable anywhere in the function, but only access its value, Python will use the global variable by that name if one exists. So you could do:
G = None
def foo():
if G is None:
print G
foo()
This code prints None and does not throw the UnboundLocalError.
You still have to declare G as global, from within that function:
G = None
def foo():
global G
if G is None:
G = 1
foo()
print G
which simply outputs
1
Define G as global in the function like this:
#!/usr/bin/python
G = None;
def foo():
global G
if G is None:
G = 1;
print G;
foo();
The above python prints 1.
Using global variables like this is bad practice because: http://c2.com/cgi/wiki?GlobalVariablesAreBad