Concepts about Local and Global Variables in Python - python

please check the code below.
x = 10
z = 30
def Rohan():
y = 15
x = 20
print(x,y,z)
global z
global x
z += 5
print (x,y,z)
Rohan()
While calling Rohan(), I am getting an error that reads "SyntaxError: name 'z' is used prior to global declaration
"
Please help me with the concepts of Global Variables and Local variables and what's causing the error.

Related

Why is global keyword not ignored even if it is unreachable? (Python)

I am really new to programming and Python, so please really forgive me for my ignorance.
I just learned that using global can make a variable inside function be a global one.
However, I discovered something not with my expectation:
I tried the following code in Python 3.8 (forgive me for my ignorance as I don't know what else information I should provide):
>>> x = 0
>>>
>>> def function():
... if False:
... global x
... x = 1
...
>>> function()
>>> print(x)
and the result is 1.
However, I expected the code to have the same effect as the following code:
>>> x = 0
>>>
>>> def function():
... x = 1
...
>>> function()
>>> print(x)
which the result should be 0.
In my mind, the statement inside if False should not be executed, so it sounds strange to me.
Also, personally, I think that in some situation I would expect the variable inside a function, whether local or global, to be dependent on other codes... what I mean is, I would like to change if False to something like if A == 'A', while (I hope) I can control whether the x is global/local according to my conditional statement.
I tried to change if to while, but it's the same... there isn't a infinite loop, but the code global x is still executed/compiled...
I admit that it may sounds naive, and perhaps it just won't work in Python, but I really wonder why... It seems that the code global x is unreachable, but how come it is not ignored?
Can anyone please tell me about the reason? I would like to know more about the mechanism behind compilation(?)
Any help would be appreciated, thank you!
In python the global statement (and the nonlocal statement) are very different from the normal python code. Essentially no matter where a global statement in a function is, it influences always the current codeblock, and is never "executed". You should think more of it as a compiler directive instead of a command.
Note that the statement itself must come before any usage of the variable it modifies, i.e.
print(x)
global x
is a syntax error. The global statement can only modify variable behavior in the whole codeblock, you can't first have a non-global variable that later gets global and you can also not have conditional global variable
(I couldn't really find good documentation for this behavior, here it says "The global statement is a declaration which holds for the entire current code block." and "global is a directive to the parser. It applies only to code parsed at the same time as the global statement." but that doesn't seem super clear to me.)
There are more compiler directives in python, although they don't always look like one. One is the from __future__ import statements which look like module imports but change python behavior.
Global is not in execution path but in a scope. The scope is whole function. Statements like if for don't make scopes. If you use any assignment you create local variable. The same with global or nonlocal you bind symbol to variable from outside.
As Stanislas Morbieu typed, see doc.
Programmer’s note: global is a directive to the parser. It applies only to code parsed at the same time as the global statement.
Not at execution time.
x = 1
def fun():
y = x + 1
print(f'local x = {x}, y = {y}')
fun()
print(f'global x = {x}')
# Output:
# local x = 1, y = 2
# global x = 1
In example above, y uses global x (and adds 1).
x = 1
def fun():
y = x
x = y + 1
print(f'local x = {x}')
fun()
print(f'global x = {x}')
# Output:
# UnboundLocalError: local variable 'x' referenced before assignment
Look at last example. It doesn't assign y from global x because assignment in second line creates local x and y can not read local x before x assignment. The same with:
x = 1
def fun():
if False:
x += 1
fun()
# Output
# UnboundLocalError: local variable 'x' referenced before assignment
x assignment creates local variable.
If you want to change global variable under condition you can use globals().
x = 1
def set_x(do_set, value):
if do_set:
globals()['x'] = value
print(f'global x = {x} (init)')
set_x(False, 2)
print(f'global x = {x} (false)')
set_x(True, 3)
print(f'global x = {x} (true)')
# Output
# global x = 1 (init)
# global x = 1 (false)
# global x = 3 (true)
Proxy
I you want to decide with variable you want to use later (in the same scope) you need some kind of proxy IMO.
x = 1
def fun(use_global):
x = 2 # local
scope = globals() if use_global else locals()
scope['x'] += 1
print(f'local ({use_global}): x = {scope["x"]}')
print(f'global: x = {x} (init)')
fun(False)
print(f'global: x = {x} (false)')
fun(True)
print(f'global: x = {x} (true)')
# Output:
# global: x = 1 (init)
# local (False): x = 3
# global: x = 1 (false)
# local (True): x = 2
# global: x = 2 (true)
Maybe you can think about refactoring of your code if you need it.
If you can change local variable name (if not use globals() as above), you can proxy:
use dict (like in example above)
use list (x=[1]) and usage x[0]
use object (with builtin dict), example:
class X:
def __init__(self, x):
self.x = x
x = X(1)
def fun(use_global):
global x
my_x = x if use_global else X(2)
my_x.x += 1
print(f'local ({use_global}): x = {my_x.x}')
print(f'global: x = {x.x} (init)')
fun(False)
print(f'global: x = {x.x} (false)')
fun(True)
print(f'global: x = {x.x} (true)')
# Output:
# global: x = 1 (init)
# local (False): x = 3
# global: x = 1 (false)
# local (True): x = 2
# global: x = 2 (true)
Note. Variables in Python are only references. It is way you can not change x = 1 without global (or globals()). You change reference to local value 1.
But you can change z[0] or z['x'] or z.x. Because z referents to list or dict or object and you modify it content.
See: https://realpython.com/python-variables/#object-references
You can check real object by id() function, ex. print(id(x), id(my_x)).
As per the Python documentation, global is a directive to the parser so it is taken into account before the execution, therefore it does not matter if the code is reachable or not. The variable is global for the entire scope, which is the function in your case.

Im having trouble with changing/updating global variables in python

So I was having trouble understanding the basics of global variable as I am a beginner in python. I wanted to try to change a global variable but unfortunate it didn't work. Could any of you explain and help my fix my problem. Thanks!!
global x
x = 10
def NEWX():
print (x)
x = x + 5
print (x)
print (x)
NEWX()
print(x)
#this displays 10 10 15 10
Try this refactor:
x = 10
def new_x():
global x
print(x)
x = x + 5
print (x)
print(x)
new_x()
print(x)
# prints 10 10 15 15
I was unable to run your original code, it complained about x being undefined in the function. Within the scope of the function, x is unknown. It's known at the higher scope, but not in your function. That's why the global x statement needs to be in the function - to let python know to use the x from the outer scope.
x = 10
def NEWX():
global x
print (x)
x = x + 5
print (x)
print (x)
NEWX()
print(x)
Global variable rules:
global keyword outside a function has no effect
Variable outside a function is global by default
global keyword is needed to read and write global variable within a function
In your code, you are first printing the value of x. The function NEWX(): is then called which prints x, then adds 5 onto x and prints the new value. After the function is called, x is printed again.
To understand what is happening, check out this example that contains the fix:
x = 10
def NEWX():
print (x)
global x
x = x + 5
print (x)
print (x)
NEWX()
print(x)

nonlocal statement got checked without running the function in python [duplicate]

This question already has answers here:
When is the existence of nonlocal variables checked?
(2 answers)
Closed 4 years ago.
previously I thought that when we define a function, the function can be wrong, but python will not check it until it got executed:
x = 100
def f():
x = 1/0
return x
print(x)
# >>> 100
however, when I was learning the nonlocal statement
x = 100
def f():
def g():
nonlocal x
x = x * 99
return x
return g
print(x)
# >>> SyntaxError: no binding for nonlocal 'x' found
It got checked out even if the function is not executed.
Is there anywhere I can find the official explanation for this?
Additional for variable bounding situation:
x = 100
def f():
global x
global xx
x = 99
return x
print(f())
# >>> 99
print(x)
# >>> 99
it seemed totally fine, if I global some variable that does not exist at all?
And it doesn't even bring any error even if I execute this function?
this part is moved to a new individual question:
Why am I able to global a non-existing varlable in python
The nonlocal checks the nearest enclosing scope, excluding globals (that is, module level variables). That is, your f() function should declare a x for it to work, as nonlocal can't see the global x = 100 variable.
See https://docs.python.org/3/reference/simple_stmts.html#the-global-statement.
As to why the error is raised without running the function, it is because the variable names are bound at compile-time, so it doesn't matter that you don't use this function at all. See
https://docs.python.org/3/reference/executionmodel.html#resolution-of-names
However, global has different behaviour. Just like nonlocal if the global x already exists, it is used instead of the local one. However, if it doesn't, it means "if I create a variable named x, create it on the global scope, instead of the function scope". So, in your example
x = 100
def f():
global x
global xx
x = 99
xx = 123
return x
print(f()) # 99
print(x) # 99
print(xx) # 123
a xx variable has appeared in the global namespace. It is only a hint to the compiler though, so if you declared global xx without assigning it, and try to print(xx) later, you still get a NameError for using an undefined variable

Pyglet: variables in on_draw

My code uses on_draw() to display some figures, it uses global variables as the parameters of those figures.
I would like to know how to send local variables from the main() function to on_draw().
Is it possible?
I'm not familiar with Pyglet, but I'll try and answer.
If you want to use global variables from main(), declare the variables from within the on_draw() with the global keyword.
For example in the global space (outside of any functions).
x = 5
In your on_draw():
global x
#whenever you refer to x from now on, you will be referring to the x from main
#do something with x
x = 10
Now if you're in your main() again:
global x
print(x)
> 10
To add to Lee Thomas's answer, here is a complete snippet that can actually perform actions based on the value of the variable anywhere in the code:
import pyglet
x = 0 #declaring a global variable
window = pyglet.window.Window()#fullscreen=True
one_image = pyglet.image.load("one.png")
two_image = pyglet.image.load("two.png")
x = 10 #assigning the variable with a different value
one = pyglet.sprite.Sprite(one_image)
two = pyglet.sprite.Sprite(two_image)
print "x in main, ", x
#window.event
def on_draw():
global x #making the compiler understand that the x is a global one and not local
one.x = 0
one.y = 0
one.draw()
two.x = 365
two.y = 305
two.draw()
print "x in on_draw, ", x
pyglet.app.run()
Once I run the code, I get the output
Hope this helps

Why can I access a non-global variable in one module from another in python?

Ok, the below code is completely scrap, pointless code I made up; but I find it weird that I can access the variable "b" from the qwerty() function while b was only declared inside while... I thought I could only access it if I declared it globally somehow?
x = 14
while (x > 10):
b = 3
b += 3
print(b)
x -= 1
def qwerty():
if b == 6:
print("b can be accessed elsewhere?")
input("")
Running this code, "b can be accessed elsewhere?" will be printed... even though b == 6 is referencing the variable b that was declared in the separate while() function.
I guess I am still confused about the properties of global and local variables in python. Can anyone explain why the above happens?
while is not a function. The only constructs that create their own scopes are def, class, and generator expressions / comprehensions (depending on version).
if True:
while 1:
for x in range(1):
z = 1
break
def function():
print(z)
function() # prints 1
This works almost the same way as inside functions.
def function():
while True:
x = 5
break
def nested():
print(x)
nested() # prints 5
x = 10
nested() # prints 10
I say almost because there are a few subtle differences in how you can modify outer variables depending on whether they are global or belong to an enclosing function.

Categories