Using a variable from a different subprogram [duplicate] - python

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 8 years ago.
I need to create program code in python that uses a defined variable from a different subprogram using a simple version:
x = 'ham'
def a():
x = 'cheese'
def b():
print(x)
a()
b()
How do I get this to save the global variable x as cheese instead of ham?

Whenever you mutate a global variable in a function, you have to explicitly declare that you're using it as a global:
x = 1
def a():
global x
x = 4
def b():
print(x)
a()
b()
Otherwise, a just creates a local variable x that shadows the global.

I'm guessing by subprogram you mean function?
The reason you are getting a 1 instead of a 4 is because x = 1 sets a global variable (in the global scope).
When you do x = 4 inside of a function it creates a local variable (in that function's local scope). Once the function is finished, the local variables are discarded.
When you call b() and it tries to look up the value of x, there is no local variable x (in b's local scope) so it uses the global variable x, which is 1.
If you want a() to modify the global variable x, you have to options:
1) You can just modify the global variable explicitly
def a():
global x
x = 4
2) You can return the local varaible and assign it to the global (preferred)
def a():
x = 4
return x
x = a()

Related

Why do I have do "global" a variable that's already global? [duplicate]

What is a global statement? And how is it used? I have read Python's official definition;
however, it doesn't make a lot of sense to me.
Every "variable" in python is limited to a certain scope. The scope of a python "file" is the module-scope. Consider the following:
#file test.py
myvariable = 5 # myvariable has module-level scope
def func():
x = 3 # x has "local" or function level scope.
Objects with local scope die as soon as the function exits and can never be retrieved (unless you return them), but within a function, you can access variables in the module level scope (or any containing scope):
myvariable = 5
def func():
print(myvariable) # prints 5
def func2():
x = 3
def func3():
print(x) # will print 3 because it picks it up from `func2`'s scope
func3()
However, you can't use assignment on that reference and expect that it will be propagated to an outer scope:
myvariable = 5
def func():
myvariable = 6 # creates a new "local" variable.
# Doesn't affect the global version
print(myvariable) # prints 6
func()
print(myvariable) # prints 5
Now, we're finally to global. The global keyword is the way that you tell python that a particular variable in your function is defined at the global (module-level) scope.
myvariable = 5
def func():
global myvariable
myvariable = 6 # changes `myvariable` at the global scope
print(myvariable) # prints 6
func()
print(myvariable) # prints 6 now because we were able
# to modify the reference in the function
In other words, you can change the value of myvariable in the module-scope from within func if you use the global keyword.
As an aside, scopes can be nested arbitrarily deeply:
def func1():
x = 3
def func2():
print("x=",x,"func2")
y = 4
def func3():
nonlocal x # try it with nonlocal commented out as well. See the difference.
print("x=",x,"func3")
print("y=",y,"func3")
z = 5
print("z=",z,"func3")
x = 10
func3()
func2()
print("x=",x,"func1")
func1()
Now in this case, none of the variables are declared at the global scope, and in python2, there is no (easy/clean) way to change the value of x in the scope of func1 from within func3. That's why the nonlocal keyword was introduced in python3.x . nonlocal is an extension of global that allows you to modify a variable that you picked up from another scope in whatever scope it was pulled from.
mgilson did a good job but I'd like to add some more.
list1 = [1]
list2 = [1]
def main():
list1.append(3)
#list1 = [9]
list2 = [222]
print list1, list2
print "before main():", list1, list2
>>> [1] [1]
main()
>>> [1,3] [222]
print list1, list2
>>> [1, 3] [1]
Inside a function, Python assumes every variable as local variable
unless you declare it as global, or you are accessing a global variable.
list1.append(2)
was possible because you are accessing the 'list1' and lists are mutable.
list2 = [222]
was possible because you are initializing a local variable.
However if you uncomment #list1 = [9], you will get
UnboundLocalError: local variable 'list1' referenced before assignment
It means you are trying to initialize a new local variable 'list1' but it was already referenced before,
and you are out of the scope to reassign it.
To enter the scope, declare 'list1' as global.
I strongly recommend you to read this even though there is a typo in the end.
a = 1
def f():
a = 2 # doesn't affect global a, this new definition hides it in local scope
a = 1
def f():
global a
a = 2 # affects global a
Basically it tells the interpreter that the variable its given should be modified or assigned at the global level, rather than the default local level.
You can use a global variable in other functions by declaring it as global in each function that modifies it
Python wants to make sure that you really know that's what you're playing with by explicitly requiring the global keyword.
See this answer

Could some explain the following behavior of global variable in python? [duplicate]

This question already has answers here:
In Python what is a global statement?
(5 answers)
Closed 4 years ago.
test.py
x = 10; # global variable
def func1():
print(x); # prints 10
def func2()
x = x + 1; # IDE shows error: "Unresolved reference of x(RHS of expression)
def func3()
global x;
x = x + 1; # This works
When x has a global scope, why doesn't func2() allow me to modify its value though it is accessible as seen in func1(). And why does it require explicit mention of "global" keyword as in case of func3() ?
You can access global variables but for modifying them it should be explicitly declared that variable is a global variable.
I think this link would be useful.
The reason behind it is that when you say x = x + 1, python thinks that you want a local variable x and then when reaches the x + 1 expression python finds out that the local variable x was mentioned but not assigned any value so it gets confused.

Nested function definitions and scope (UnboundLocalError) [duplicate]

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 5 months ago.
Why is the following code invalid:
def foo1(x=5):
def bar():
if x == 5:
x = 6
print(x)
bar()
While this code is valid:
def foo2(x=5):
def bar():
if x == 5:
print('ok')
print(x)
bar()
foo2() will do exactly what you expect, but foo1() will give a UnboundLocalError: local variable 'x' referenced before assignment at the line if x == 5:. Why does altering the value of x later on in the code make this conditional invalid?
Python needs first to detect what variables are local, and which variable are fetched from an outer scope. In order to do that it looks for assignments, like:
def foo1(x=5):
def bar():
if x == 5:
x = 6 # an assignment, so local variable
print(x)
bar()
The point is, that the assignment can happen anywhere. For instance on the last line. Nevertheless, from the moment there is an assignment somewhere x is local. So in your first code fragment, x is a local variable. But you fetch it before it is assigned (bounded), so Python will error on it.
In python-3.x you can use the nonlocal keyword to access x from an outer scope:
def foo1(x=5):
def bar():
nonlocal x
if x == 5:
x = 6
print(x)
bar()
For python-2.x, you can for instance assign the variable to the function, like:
def foo1(x=5):
def bar():
if bar.x == 5:
bar.x = 6
print(bar.x)
bar.x = x
bar()
Note however that the two are not equivalent. Since in the former if you alter x, it will be alter the x in the foo1 scope as well. In the latter example you only modify bar.x. Of course if these are mutable objects, you alter the same object.

Python: Follow up regarding variable scope. Why can I change the global value of x.a within def A?

As a follow up to this question
Why can I change the global value of x.a within def A? I am guessing it has to do with the fact that it is a class since it would not work with a regular variable because it would be redefined in the local scope of def A, but I am not quite understanding what is happening.
Case 1
class X:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
class Y:
def A(self):
print(x.a,x.b,x.c)
x.a = 4
x = X()
y = Y()
y.A()
print(x.a,x.b,x.c)
If you set x = Y() in A scope it would create a local x in that scope. In this case however, you are not setting x, you are setting x.a. Looking up variables takes into account global variables too. Imagine you are doing this instead setattr(x, "a", 4) and it will make more sense.
Also if I remember correctly you can "import" global variables into a function scope by using the global keyword. (see Use of "global" keyword in Python)
Global names can be read within functions:
x = 5
def read_x():
print(x)
Globals that reference mutable types can also be mutated within functions:
x = [1, 2, 3]
def mutate_x():
x[0] = 'One'
What you can't do to a global within the scope of a function is assignment:
x = 5
def set_x():
# this simply assigns a variable named x local to this function -- it doesn't modify the global x
x = 3
# now, back outside the scope of set_x, x remains 5
print(x)
5
Unless you explicitly declare the global within the scope of the function:
x = 5
def set_x():
global x
x = 3
# back outside the function's scope
print(x)
3
What you're doing in your example is "mutating" -- modifying an attribute of an object. Assigning a value to an attribute of a user-defined type is one example of mutation, just like modifying an element of a list or a dictionary. That's why this works.
The class A doesn't have an init method that defines x, so the method A, when you try to access the attribute a of x, try to find the x object in the local scope, and since it can't find it then it looks the outside scope where an object name x is present, it grabs that object and override the attribute a.
So basically what you are doing is modify the actual attribute a of the object x that you create before you call y.A().
It's the very basic foundation of a closure: access a variable that is defined outside the local scope.

In Python what is a global statement?

What is a global statement? And how is it used? I have read Python's official definition;
however, it doesn't make a lot of sense to me.
Every "variable" in python is limited to a certain scope. The scope of a python "file" is the module-scope. Consider the following:
#file test.py
myvariable = 5 # myvariable has module-level scope
def func():
x = 3 # x has "local" or function level scope.
Objects with local scope die as soon as the function exits and can never be retrieved (unless you return them), but within a function, you can access variables in the module level scope (or any containing scope):
myvariable = 5
def func():
print(myvariable) # prints 5
def func2():
x = 3
def func3():
print(x) # will print 3 because it picks it up from `func2`'s scope
func3()
However, you can't use assignment on that reference and expect that it will be propagated to an outer scope:
myvariable = 5
def func():
myvariable = 6 # creates a new "local" variable.
# Doesn't affect the global version
print(myvariable) # prints 6
func()
print(myvariable) # prints 5
Now, we're finally to global. The global keyword is the way that you tell python that a particular variable in your function is defined at the global (module-level) scope.
myvariable = 5
def func():
global myvariable
myvariable = 6 # changes `myvariable` at the global scope
print(myvariable) # prints 6
func()
print(myvariable) # prints 6 now because we were able
# to modify the reference in the function
In other words, you can change the value of myvariable in the module-scope from within func if you use the global keyword.
As an aside, scopes can be nested arbitrarily deeply:
def func1():
x = 3
def func2():
print("x=",x,"func2")
y = 4
def func3():
nonlocal x # try it with nonlocal commented out as well. See the difference.
print("x=",x,"func3")
print("y=",y,"func3")
z = 5
print("z=",z,"func3")
x = 10
func3()
func2()
print("x=",x,"func1")
func1()
Now in this case, none of the variables are declared at the global scope, and in python2, there is no (easy/clean) way to change the value of x in the scope of func1 from within func3. That's why the nonlocal keyword was introduced in python3.x . nonlocal is an extension of global that allows you to modify a variable that you picked up from another scope in whatever scope it was pulled from.
mgilson did a good job but I'd like to add some more.
list1 = [1]
list2 = [1]
def main():
list1.append(3)
#list1 = [9]
list2 = [222]
print list1, list2
print "before main():", list1, list2
>>> [1] [1]
main()
>>> [1,3] [222]
print list1, list2
>>> [1, 3] [1]
Inside a function, Python assumes every variable as local variable
unless you declare it as global, or you are accessing a global variable.
list1.append(2)
was possible because you are accessing the 'list1' and lists are mutable.
list2 = [222]
was possible because you are initializing a local variable.
However if you uncomment #list1 = [9], you will get
UnboundLocalError: local variable 'list1' referenced before assignment
It means you are trying to initialize a new local variable 'list1' but it was already referenced before,
and you are out of the scope to reassign it.
To enter the scope, declare 'list1' as global.
I strongly recommend you to read this even though there is a typo in the end.
a = 1
def f():
a = 2 # doesn't affect global a, this new definition hides it in local scope
a = 1
def f():
global a
a = 2 # affects global a
Basically it tells the interpreter that the variable its given should be modified or assigned at the global level, rather than the default local level.
You can use a global variable in other functions by declaring it as global in each function that modifies it
Python wants to make sure that you really know that's what you're playing with by explicitly requiring the global keyword.
See this answer

Categories

Resources