global and nonlocal variable in Python

Most of us are already familiar with global variables in Python. If we declare those variables in a module, the functions inside that module (can read python file or .py file) can access the variable. For example, check the code below :

x = 5

def myfnc():
print("inside myfnc", x)
def myfnc2():
print("inside myfnc2", x)

myfnc2()

myfnc()

It will print : 
inside myfnc 5
inside myfnc2 5

If you change your code like this :

x = 5

def myfnc():
print("inside myfnc", x)
def myfnc2():
print("inside myfnc2", x)
x = 10
print("x = ", x)

myfnc2()

myfnc()

You will get an error :

  File "program.py", line 6, in myfnc2
    print("inside myfnc2", x)
UnboundLocalError: local variable 'x' referenced before assignment

The moment you wrote x = 10, Python assume that x is a local variable, and inside the print function, it is giving this error. Because local variables are determined at compile time (from official doc : "local variables are already determined statically").  You can get rid of the error, if you declare x as global.

x = 5

def myfnc():
print("inside myfnc", x)
def myfnc2():
global x
print("inside myfnc2", x)
x = 10
print("x = ", x)

myfnc2()

myfnc()

Now you can run the program again. It won't throw any error. What if we code like this now?

x = 5

def myfnc():
print("inside myfnc", x)
y = 10
def myfnc2():
global x
print("inside myfnc2", x, y)
x = 10
print("x = ", x)

myfnc2()

myfnc()

If you run the program, you will see desired output. But now, if you want to write to y inside myfnc2() (for example, assign something like y = 1), you can't use global y, as y is not a global variable. You can try this following code that fails successfully :

x = 5

def myfnc():
print("inside myfnc", x)
y = 10
def myfnc2():
global x
global y
print("inside myfnc2", x, y)
x = 10
print("x = ", x)
y = 1
print("y = ", y)

myfnc2()

myfnc()

You will get this error : NameError: name 'y' is not defined

We need to understand that, y is not a global variable. Here nonlocal can help! Instead of global y, just write nonlocal. It will make y available and writable inside myfnc2(). 

x = 5

def myfnc():
print("inside myfnc", x)
y = 10
def myfnc2():
global x
nonlocal y
print("inside myfnc2", x, y)
x = 10
print("x = ", x)
y = 1
print("y = ", y)

myfnc2()

myfnc()

This is something I learnt today. :)

Comments

Balaswamy said…
Wait a minute ... Non local and global both are same..??
Tamim Shahriar said…
No, they are not same.
r2evans said…
A good reference for the difference between `nonlocal` and `global` is straight from the source: https://docs.python.org/3/reference/simple_stmts.html. Briefly:

- `global`: Names listed in a global statement must not be defined as formal parameters or in a for loop control target, class definition, function definition, import statement, or variable annotation.

- `nonlocal`: Names listed in a nonlocal statement, unlike those listed in a global statement, must refer to pre-existing bindings in an enclosing scope ...

In this case, `x` is not considered within an enclosing scope, so it can be accessed only with `global x`. Likewise, `y` is within a function definition so must be `nonlocal y`. I would have thought that the enclosing scope would have found `x` in the global environment, so I'll need to brush up on why `nonlocal x` fails (with `SyntaxError: no binding for nonlocal 'x' found`).

Popular posts from this blog

Strip HTML tags using Python

lambda magic to find prime numbers

Convert text to ASCII and ASCII to text - Python code