This question already has answers here:
Using global variables in a function
(25 answers)
Closed 5 months ago.
I know I should avoid using global variables in the first place due to confusion like this, but if I were to use them, is the following a valid way to go about using them? (I am trying to call the global copy of a variable created in a separate function.)
x = "somevalue"
def func_A ():
global x
# Do things to x
return x
def func_B():
x = func_A()
# Do things
return x
func_A()
func_B()
Does the x that the second function uses have the same value of the global copy of x that func_a uses and modifies? When calling the functions after definition, does order matter?
If you want to simply access a global variable you just use its name. However to change its value you need to use the global keyword.
E.g.
global someVar
someVar = 55
This would change the value of the global variable to 55. Otherwise it would just assign 55 to a local variable.
The order of function definition listings doesn't matter (assuming they don't refer to each other in some way), the order they are called does.
Within a Python scope, any assignment to a variable not already declared within that scope creates a new local variable unless that variable is declared earlier in the function as referring to a globally scoped variable with the keyword global.
Let's look at a modified version of your pseudocode to see what happens:
# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'
def func_A():
# The below declaration lets the function know that we
# mean the global 'x' when we refer to that variable, not
# any local one
global x
x = 'A'
return x
def func_B():
# Here, we are somewhat mislead. We're actually involving two different
# variables named 'x'. One is local to func_B, the other is global.
# By calling func_A(), we do two things: we're reassigning the value
# of the GLOBAL x as part of func_A, and then taking that same value
# since it's returned by func_A, and assigning it to a LOCAL variable
# named 'x'.
x = func_A() # look at this as: x_local = func_A()
# Here, we're assigning the value of 'B' to the LOCAL x.
x = 'B' # look at this as: x_local = 'B'
return x # look at this as: return x_local
In fact, you could rewrite all of func_B with the variable named x_local and it would work identically.
The order matters only as far as the order in which your functions do operations that change the value of the global x. Thus in our example, order doesn't matter, since func_B calls func_A. In this example, order does matter:
def a():
global foo
foo = 'A'
def b():
global foo
foo = 'B'
b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.
Note that global is only required to modify global objects. You can still access them from within a function without declaring global.
Thus, we have:
x = 5
def access_only():
return x
# This returns whatever the global value of 'x' is
def modify():
global x
x = 'modified'
return x
# This function makes the global 'x' equal to 'modified', and then returns that value
def create_locally():
x = 'local!'
return x
# This function creates a new local variable named 'x', and sets it as 'local',
# and returns that. The global 'x' is untouched.
Note the difference between create_locally and access_only -- access_only is accessing the global x despite not calling global, and even though create_locally doesn't use global either, it creates a local copy since it's assigning a value.
The confusion here is why you shouldn't use global variables.
You can directly access a global variable inside a function. If you want to change the value of that global variable, use "global variable_name". See the following example:
var = 1
def global_var_change():
global var
var = "value changed"
global_var_change() #call the function for changes
print var
Generally speaking, this is not a good programming practice. By breaking namespace logic, code can become difficult to understand and debug.
As others have noted, you need to declare a variable global in a function when you want that function to be able to modify the global variable. If you only want to access it, then you don't need global.
To go into a bit more detail on that, what "modify" means is this: if you want to re-bind the global name so it points to a different object, the name must be declared global in the function.
Many operations that modify (mutate) an object do not re-bind the global name to point to a different object, and so they are all valid without declaring the name global in the function.
d = {}
l = []
o = type("object", (object,), {})()
def valid(): # these are all valid without declaring any names global!
d[0] = 1 # changes what's in d, but d still points to the same object
d[0] += 1 # ditto
d.clear() # ditto! d is now empty but it`s still the same object!
l.append(0) # l is still the same list but has an additional member
o.test = 1 # creating new attribute on o, but o is still the same object
Here is one case that caught me out, using a global as a default value of a parameter.
globVar = None # initialize value of global variable
def func(param = globVar): # use globVar as default value for param
print 'param =', param, 'globVar =', globVar # display values
def test():
global globVar
globVar = 42 # change value of global
func()
test()
=========
output: param = None, globVar = 42
I had expected param to have a value of 42. Surprise. Python 2.7 evaluated the value of globVar when it first parsed the function func. Changing the value of globVar did not affect the default value assigned to param. Delaying the evaluation, as in the following, worked as I needed it to.
def func(param = eval('globVar')): # this seems to work
print 'param =', param, 'globVar =', globVar # display values
Or, if you want to be safe,
def func(param = None)):
if param == None:
param = globVar
print 'param =', param, 'globVar =', globVar # display values
You must use the global declaration when you wish to alter the value assigned to a global variable.
You do not need it to read from a global variable. Note that calling a method on an object (even if it alters the data within that object) does not alter the value of the variable holding that object (absent reflective magic).
Related
class Something:
x = "hi"
def func(self):
k = "hi2"
In this piece of code, x as a class attribute and k as a variable. What scope (local, enclosed, global, builtin) would x belong to and what scope would k belong to?
You say you don't want an answer like "in the scope of the function" or "-- the class", but that would be the most precise answer. A scope like local is always relative to where you are.
If you are in the global scope, then only the class itself is in both the local and global scope (which are the same then), but neither of the variables are. You can access x via the class, but k will only be defined when the function is called.
If you are inside of func, then k and self are in the local scope, but x is in neither the local nor global scope. It is not in the enclosed scope either; it can not be accessed directly, as in print(x), but only via the instance self or the class Something.
class Something:
x = "hi"
def func(self):
k = "hi2"
print(locals()) # contains k, self
print(globals()) # contains Something
print(k) # works
print(self.x) # works
print(Something.x) # works
print(x) # does not work
Something().func()
The case is different with nested functions. Here, variables defined in the outer functions are in the "enclosing scope", but may be promoted to the local scope by using them:
def f():
a = []
def g():
b = None
# a = [] # define a new a in local scope?
# a.append(42) # without above line, this changes enclosed a
print(locals()) # only b, unless you use a here
g()
print(a)
f()
if you leave the commented lines as they are, only b in in the inner local scope
if you activate the append line, a from the enclosing scope is moved to the local scope and changed in both scopes
if you activate both commented lines, a new a is defined in the local scope without changing the a in the enclosing scope
The following code #1 requires nonlocal previous_score
def announce_max(previous_score = 0):
"""
print the max of all scores
>>> f0 = announce_max()
>>> f1 = f0(5)
5
>>> f2 = f1(2)
5
>>> f3 = f2(3)
5
>>> f4 = f3(7)
7
"""
def say(current_score):
nonlocal previous_score
previous_score = max(previous_score, current_score)
print(previous_score)
return announce_max(previous_score)
return say
The following code #2 does NOT require nonlocal previous_score
def announce_max(previous_score = 0):
"""
print the max of all scores
>>> f0 = announce_max()
>>> f1 = f0(5)
5
>>> f2 = f1(2)
5
>>> f3 = f2(3)
5
>>> f4 = f3(7)
7
"""
def say(current_score):
# nonlocal previous_score
print(max(previous_score, current_score))
return announce_max(max(previous_score, current_score))
return say
Why do we need nonlocal previous_score in code #1 above, do we call it outside the function say?
If yes, why code #2 works?
You need it when you assign to the name, and want to change the closure scoped variable. The act of assignment is what makes a name a local in a function (and it is a local from the beginning of the function, it doesn't switch roles at the moment of assignment); nonlocal and global declarations are what undoes that automatic creation of a local name.
So long as you don't assign to it, reading from that name invokes LEGB lookup, logically checking the local scope first, then enclosing scope(s), then global, then built-in scope. In practice, a name's presence in local or enclosing scopes is statically determined, so at most two scopes are ever checked (when it's not local or enclosing, it checks the global scope first, and falls back to built-in scope if a name being read is not in global scope).
The second version of your function do not work as intended - it will not update the maximum previous score as in the first function.
What is relevant is: outter-scope variables are always readable from nested functions, but they cannot be updated.
If your second function would try to update previous_score without the non local declaration, the function would error with NameError in the line you try to read the value in previous_score to calculate the max. That is: if the name is written to in the nested function, Python assumes it to be local to the function, unless it is explicitly declared as nonlocal or as global. In that case, in the following code, the previous_score local to say would not be assigned when calling max:
# this is broken:
def announce_max(previous_score = 0):
def say(current_score):
previous_score = max(previous_score, current_score)
print(previous_score)
return announce_max(previous_score)
return say
The following does have the variable declared before the function however when printing the variable within the function the value desired is outputted however when printed after the function the value of the variable remains the same as it did when declared.
foo = 0
def method(bar, baz):
foo = bar + baz
print(foo)
return foo
method(1, 3)
print(foo)
With the use of global variables the desired value is outputted however I would prefer an answer that does not contain global variables.
I'm not entirely sure this is what you want, since strictly speaking you cannot have a global variable without having a global variable. What you can do is having a mutable global variable which you can modify without an explicit global.
foo = [] # list is mutable, just like dict, set, ...
def method(bar, baz):
foo[:] = [bar + baz] # replace foo's *elements* via [:]
print(foo)
return foo
method(1, 3)
print(foo)
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
This question already has answers here:
Using global variables in a function
(25 answers)
Closed 6 months ago.
I know I should avoid using global variables in the first place due to confusion like this, but if I were to use them, is the following a valid way to go about using them? (I am trying to call the global copy of a variable created in a separate function.)
x = "somevalue"
def func_A ():
global x
# Do things to x
return x
def func_B():
x = func_A()
# Do things
return x
func_A()
func_B()
Does the x that the second function uses have the same value of the global copy of x that func_a uses and modifies? When calling the functions after definition, does order matter?
If you want to simply access a global variable you just use its name. However to change its value you need to use the global keyword.
E.g.
global someVar
someVar = 55
This would change the value of the global variable to 55. Otherwise it would just assign 55 to a local variable.
The order of function definition listings doesn't matter (assuming they don't refer to each other in some way), the order they are called does.
Within a Python scope, any assignment to a variable not already declared within that scope creates a new local variable unless that variable is declared earlier in the function as referring to a globally scoped variable with the keyword global.
Let's look at a modified version of your pseudocode to see what happens:
# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'
def func_A():
# The below declaration lets the function know that we
# mean the global 'x' when we refer to that variable, not
# any local one
global x
x = 'A'
return x
def func_B():
# Here, we are somewhat mislead. We're actually involving two different
# variables named 'x'. One is local to func_B, the other is global.
# By calling func_A(), we do two things: we're reassigning the value
# of the GLOBAL x as part of func_A, and then taking that same value
# since it's returned by func_A, and assigning it to a LOCAL variable
# named 'x'.
x = func_A() # look at this as: x_local = func_A()
# Here, we're assigning the value of 'B' to the LOCAL x.
x = 'B' # look at this as: x_local = 'B'
return x # look at this as: return x_local
In fact, you could rewrite all of func_B with the variable named x_local and it would work identically.
The order matters only as far as the order in which your functions do operations that change the value of the global x. Thus in our example, order doesn't matter, since func_B calls func_A. In this example, order does matter:
def a():
global foo
foo = 'A'
def b():
global foo
foo = 'B'
b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.
Note that global is only required to modify global objects. You can still access them from within a function without declaring global.
Thus, we have:
x = 5
def access_only():
return x
# This returns whatever the global value of 'x' is
def modify():
global x
x = 'modified'
return x
# This function makes the global 'x' equal to 'modified', and then returns that value
def create_locally():
x = 'local!'
return x
# This function creates a new local variable named 'x', and sets it as 'local',
# and returns that. The global 'x' is untouched.
Note the difference between create_locally and access_only -- access_only is accessing the global x despite not calling global, and even though create_locally doesn't use global either, it creates a local copy since it's assigning a value.
The confusion here is why you shouldn't use global variables.
You can directly access a global variable inside a function. If you want to change the value of that global variable, use "global variable_name". See the following example:
var = 1
def global_var_change():
global var
var = "value changed"
global_var_change() #call the function for changes
print var
Generally speaking, this is not a good programming practice. By breaking namespace logic, code can become difficult to understand and debug.
As others have noted, you need to declare a variable global in a function when you want that function to be able to modify the global variable. If you only want to access it, then you don't need global.
To go into a bit more detail on that, what "modify" means is this: if you want to re-bind the global name so it points to a different object, the name must be declared global in the function.
Many operations that modify (mutate) an object do not re-bind the global name to point to a different object, and so they are all valid without declaring the name global in the function.
d = {}
l = []
o = type("object", (object,), {})()
def valid(): # these are all valid without declaring any names global!
d[0] = 1 # changes what's in d, but d still points to the same object
d[0] += 1 # ditto
d.clear() # ditto! d is now empty but it`s still the same object!
l.append(0) # l is still the same list but has an additional member
o.test = 1 # creating new attribute on o, but o is still the same object
Here is one case that caught me out, using a global as a default value of a parameter.
globVar = None # initialize value of global variable
def func(param = globVar): # use globVar as default value for param
print 'param =', param, 'globVar =', globVar # display values
def test():
global globVar
globVar = 42 # change value of global
func()
test()
=========
output: param = None, globVar = 42
I had expected param to have a value of 42. Surprise. Python 2.7 evaluated the value of globVar when it first parsed the function func. Changing the value of globVar did not affect the default value assigned to param. Delaying the evaluation, as in the following, worked as I needed it to.
def func(param = eval('globVar')): # this seems to work
print 'param =', param, 'globVar =', globVar # display values
Or, if you want to be safe,
def func(param = None)):
if param == None:
param = globVar
print 'param =', param, 'globVar =', globVar # display values
You must use the global declaration when you wish to alter the value assigned to a global variable.
You do not need it to read from a global variable. Note that calling a method on an object (even if it alters the data within that object) does not alter the value of the variable holding that object (absent reflective magic).