Names assigned inside a function are local to that function unless we declare them as global or nonlocal.
n=5 # global
def my_fun():
n=6 # local variable
print("Inside function : ", n)
my_fun()
print("Outside function :",n )
Output
Inside function : 6
Outside function : 5
The global variable n remains unchanged because the assignment inside the function creates a separate local variable.
n=5
def my_fun():
n=10 # local variable
n=n+1
print("Inside function : ", n )
my_fun()
print("Outside function:",n) # print value of global variable n
Output: The local change does not affect the global value of n.
Inside function : 11
Outside function: 5
We can read a global variable inside a function without using global. We use the global keyword when we want an assignment inside the function to change the module-level variable.
n=5
def my_fun():
global n
n= n+1
print("Inside function : ", n)
my_fun()
n= n+1
print("Outside function :", n)
Output
Inside function : 6
Outside function : 7
When we declare n as global, assignments inside the function update the module-level variable. The changed value is therefore available outside the function.
n=5
def my_fun():
global n
n= n+1
print("Inside function : ", n)
my_fun() # 6
n= n+1
print("Outside function (first ): ",n) # 7
my_fun() # 8
n=n+1
print("Outside function (second): ",n) # 9
Output
Inside function : 6
Outside function (first ): 7
Inside function : 8
Outside function (second): 9
Python searches for a name in a defined order. The order is Local, Enclosing, Global and Built-in, commonly called the LEGB rule.
name = "Global"
def outer():
name = "Enclosing"
def inner():
name = "Local"
print(name)
inner()
outer()
Output:
Local
Use case: The LEGB rule helps us understand which value Python will use when the same variable name exists in several scopes.
We use the nonlocal keyword inside a nested function when we want to change a variable that belongs to an enclosing function.
Compare the following two examples. In the first example, my_fun2() creates its own local variable n. In the second example, nonlocal n makes the inner function update the variable from my_fun1().
n=5
def my_fun1():
n=10
def my_fun2():
n=20
print("Inside n:",n) # 20
my_fun2()
print("Outside n :",n) # 10
my_fun1()
print("Main n :",n) # 5
Output
Inside n: 20
Outside n : 10
Main n : 5
With nonlocal
n=5
def my_fun1():
n=10
def my_fun2():
nonlocal n
n=20
print("Inside n:",n) # 20
my_fun2()
print("Outside n :",n) # 20
my_fun1()
print("Main n :",n) # 5
Output
Inside n: 20
Outside n : 20
Main n : 5
The main difference between global and nonlocal is the scope of the variable we want to change.
We use global when the variable is defined outside all functions.
x = 10
def change_value():
global x
x = 20
change_value()
print(x)
Output:
20
We use nonlocal when the variable belongs to an enclosing function.
def outer():
x = 10
def inner():
nonlocal x
x = 20
inner()
print(x)
outer()
Output:
20
Simple rule: Use global for a module-level variable. Use nonlocal for a variable in an enclosing function.
We do not need the global keyword when a function only reads a variable from the module-level scope. Python searches outside the local function scope when it cannot find the name locally.
tax_rate = 18
def show_tax_rate():
print(tax_rate)
show_tax_rate()
Output:
18
Use case: We can use this approach when several functions need to read a fixed configuration value such as a tax rate, application name, or conversion factor.
A common error appears when we read a global name and later assign to the same name inside the function. Because an assignment exists inside the function, Python treats that name as local for the complete function.
score = 50
def update_score():
print(score)
score = 60
update_score()
The function raises an UnboundLocalError before it can assign 60.
If our intention is to modify the global name, we can declare it with global.
score = 50
def update_score():
global score
print(score)
score = 60
update_score()
print(score)
Output:
50
60
Use case: This distinction helps us debug functions that read a variable correctly until we add an assignment to the same variable.
Statements such as +=, -=, and *= both read and assign a value. Python therefore treats the target as local when we use an augmented assignment inside a function.
visits = 10
def add_visit():
visits += 1
add_visit()
This code raises an UnboundLocalError.
We can explicitly modify the global name when that behavior is required.
visits = 10
def add_visit():
global visits
visits += 1
add_visit()
print(visits)
Output:
11
Use case: Counters often use +=, so this issue commonly appears in beginner programs that track calls, clicks, attempts, or processed records.
There is an important difference between changing an existing object and assigning a new object to a name. We can modify the contents of a global list without declaring the list name as global.
students = ["Alex", "Ron"]
def add_student():
students.append("Ravi")
add_student()
print(students)
Output:
['Alex', 'Ron', 'Ravi']
Reassigning the name is different.
students = ["Alex", "Ron"]
def replace_students():
global students
students = ["Ravi", "Mona"]
replace_students()
print(students)
Output:
['Ravi', 'Mona']
Use case: This distinction is useful when functions update shared lists, dictionaries, or sets. It explains why methods such as append() can work without global while direct reassignment requires it.
The existing examples show how nonlocal changes a variable in an enclosing function. We can extend this concept with a practical closure that keeps a value between calls.
def create_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
my_counter = create_counter()
print(my_counter())
print(my_counter())
print(my_counter())
Output:
1
2
3
Use case: We can use this pattern for counters, sequence generators, simple state trackers, and functions that need to remember a value without using a global variable.
If several nested functions contain a variable with the same name, nonlocal works with the nearest enclosing function that already defines that name.
value = "global"
def outer():
value = "outer"
def middle():
value = "middle"
def inner():
nonlocal value
value = "changed by inner"
inner()
print("Middle:", value)
middle()
print("Outer:", value)
outer()
print("Global:", value)
Output:
Middle: changed by inner
Outer: outer
Global: global
Use case: This behavior matters when we build nested helper functions and more than one enclosing function uses the same variable name.
We cannot use nonlocal for a name that does not already exist in an enclosing function scope.
def outer():
def inner():
nonlocal total
total = 10
inner()
Python raises a SyntaxError because no enclosing function has created a variable named total.
Use case: This rule helps us identify incorrect nonlocal declarations before the program starts running.
Python functions create local scopes, but common control blocks such as if, for, and while do not create separate local scopes.
def check_number():
if 5 > 2:
message = "Condition is true"
print(message)
check_number()
Output:
Condition is true
The same behavior applies to a regular for loop.
def show_last_value():
for number in [10, 20, 30]:
pass
print(number)
show_last_value()
Output:
30
Use case: This rule explains why variables created inside loops and conditional blocks can still be available later in the same function.
A list comprehension behaves differently from a regular for loop in modern Python. Its iteration variable does not remain available outside the comprehension.
numbers = [1, 2, 3]
squares = [number * number for number in numbers]
print(squares)
print(number)
The first print statement works, but the second statement raises a NameError.
Output before the error:
[1, 4, 9]
Use case: This difference matters when we convert an existing for loop into a list comprehension and later code expects to use the loop variable.
The word global can sound as if a variable becomes available across every Python file. In practice, global refers to the global namespace of the current module.
Consider a file named settings.py.
site_name = "plus2net"
visit_count = 0
Now we use those values from another file.
import settings
def add_visit():
settings.visit_count += 1
add_visit()
add_visit()
print(settings.site_name)
print(settings.visit_count)
Output:
plus2net
2
Use case: We can use a separate module for application settings or shared state when several Python files need access to the same named values.
Global variables can be useful, but functions are usually easier to test and reuse when data enters through parameters and leaves through return values.
def increase_score(current_score, points):
return current_score + points
score = 50
score = increase_score(score, 10)
print(score)
Output:
60
Use case: This pattern works well for calculations, data processing, validation, and functions that we may reuse in different parts of a program.
We can combine enclosing scope and nonlocal to create several counters that keep independent values.
def make_counter(start):
count = start
def next_value():
nonlocal count
count += 1
return count
return next_value
counter_a = make_counter(0)
counter_b = make_counter(100)
print(counter_a())
print(counter_a())
print(counter_b())
print(counter_b())
Output:
1
2
101
102
Use case: We can use this pattern to generate independent counters, IDs, sequence numbers, or repeated-operation trackers without relying on one shared global variable.
We can use the same program to compare how global and nonlocal affect different scopes.
Keep only one declaration active inside inner(). Comment the other line, run the program, and compare the output.
x = 5 # Module-level variable
def outer():
x = 10 # Variable in the enclosing function scope
def inner():
# nonlocal x # Uncomment this to modify x from outer()
global x # Active: modifies the module-level x
x = 20
inner()
print(x) # Value of x in the enclosing function scope
outer()
print(x) # Value of the module-level x
When global x is active:
10
20
Now comment global x and uncomment nonlocal x:
x = 5 # Module-level variable
def outer():
x = 10 # Variable in the enclosing function scope
def inner():
nonlocal x # Modify x from outer()
# global x # Keep this line commented
x = 20
inner()
print(x) # Value of x in the enclosing function scope
outer()
print(x) # Value of the module-level x
Output:
20
5
Practice point: Use global when we want to modify a module-level variable. Use nonlocal when we want to modify a variable from an enclosing function.
Open our practice notebook in Google Colab and run the examples for local, global and nonlocal variables. Change the values, edit the code and compare the output.
Open Practice Notebook in Google ColabWant to view the source notebook? View it on GitHub.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.