Python Global, Local and Nonlocal Variables

Names assigned inside a function are local to that function unless we declare them as global or nonlocal.


Video Tutorial: Python Global, Local & Nonlocal Variables Explained | LEGB Scope


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

LEGB Scope Resolution in Python 🔝

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
  • Local: Python first checks names created inside the current function.
  • Enclosing: Python then checks enclosing functions when functions are nested.
  • Global: Python next checks names defined at the module level.
  • Built-in: Python finally checks built-in names such as len(), print() and range().

Use case: The LEGB rule helps us understand which value Python will use when the same variable name exists in several scopes.

Using nonlocal in Nested Functions 🔝

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

Difference Between global and nonlocal in Python 🔝

The main difference between global and nonlocal is the scope of the variable we want to change.

  • global refers to a variable in the module-level scope.
  • nonlocal refers to a variable in the nearest enclosing function scope.

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
  • The variable x is created at module level.
  • The function uses global x to update that module-level variable.

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
  • The variable x belongs to outer().
  • The inner() function uses nonlocal x to update the variable from outer().

Simple rule: Use global for a module-level variable. Use nonlocal for a variable in an enclosing function.

Reading a Global Variable Without Using global 🔝

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
  • tax_rate is created outside the function.
  • The function only reads its value.
  • We do not assign a new value to tax_rate inside the function.
  • Python therefore reads the variable from the global scope.

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.

Why Assignment Changes the Scope of a Name 🔝

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.

  • Python sees the assignment score = 60 while processing the function.
  • Python therefore treats score as a local name throughout update_score().
  • The first print() tries to read that local name before it has received a value.

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
  • The global declaration connects the name inside the function to the module-level variable.
  • The assignment changes the same score variable that exists outside the function.

Use case: This distinction helps us debug functions that read a variable correctly until we add an assignment to the same variable.

Augmented Assignment Can Also Cause UnboundLocalError 🔝

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.

  • The statement needs the current value of visits before adding 1.
  • The same statement also assigns a new value to visits.
  • Python therefore considers visits local to add_visit().
  • The local visits variable has no value when Python tries to read it.

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.

Changing a Mutable Global Object Without global 🔝

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']
  • The function does not assign a new object to the name students.
  • append() modifies the existing list object.
  • The students name still refers to the same global list.
  • We therefore do not need a global declaration in this example.

Reassigning the name is different.

students = ["Alex", "Ron"]

def replace_students():
    global students
    students = ["Ravi", "Mona"]

replace_students()
print(students)

Output:

['Ravi', 'Mona']
  • The second function assigns a completely new list to students.
  • We use global because we want to rebind the module-level name.

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.

Using nonlocal to Keep State Between Function Calls 🔝

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
  • create_counter() creates the local variable count.
  • The inner counter() function keeps access to that enclosing variable.
  • nonlocal allows counter() to update count instead of creating a new local variable.
  • The value remains available when we call my_counter() again.

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.

nonlocal Uses the Nearest Enclosing Function Scope 🔝

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
  • The nearest enclosing value belongs to middle().
  • nonlocal updates that value.
  • The value in outer() does not change.
  • The global value also remains unchanged.

Use case: This behavior matters when we build nested helper functions and more than one enclosing function uses the same variable name.

nonlocal Requires an Existing Enclosing Variable 🔝

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.

  • nonlocal does not create an enclosing variable.
  • It must refer to a name that already exists in an outer function.
  • It also does not refer directly to a module-level global variable.

Use case: This rule helps us identify incorrect nonlocal declarations before the program starts running.

if, for and while Blocks Do Not Create a New Local Scope 🔝

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
  • message is assigned inside the if block.
  • The if statement does not create another scope.
  • message belongs to the surrounding function scope.
  • We can therefore access it later in the same function if the assignment has executed.

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.

List Comprehensions Have Their Own Scope 🔝

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]
  • number exists inside the list comprehension.
  • The comprehension does not leak that iteration variable into the surrounding scope.
  • This behavior differs from a standard for loop.

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.

A global Name Belongs to the Current Module 🔝

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
  • site_name and visit_count belong to the settings module.
  • We access them through the module name.
  • A global declaration in another module would refer to that other module's namespace, not automatically to settings.py.

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.

Prefer Parameters and Return Values When Shared State Is Not Required 🔝

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
  • The function does not depend on a global score variable.
  • We clearly pass the current value into the function.
  • The function returns the updated value.
  • The same function can work with many scores without changing shared state.

Use case: This pattern works well for calculations, data processing, validation, and functions that we may reuse in different parts of a program.

Practical Example: Creating Independent Counters 🔝

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
  • Each call to make_counter() creates a separate count variable.
  • counter_a keeps its own state.
  • counter_b keeps a different state.
  • Both inner functions use nonlocal, but they do not share the same count variable.

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.

Practice: Compare global and nonlocal

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
  • global x changes the module-level variable from 5 to 20.
  • The variable x inside outer() remains 10.
  • The first print() therefore displays 10.
  • The final print() displays the changed module-level value 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
  • nonlocal x changes the variable from the enclosing outer() function.
  • The value inside outer() changes from 10 to 20.
  • The module-level variable remains unchanged at 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.

Key Points About Python Variable Scope 🔝

  • We can read a global variable inside a function without declaring it as global.
  • We need global when we assign a new value to a module-level name from inside a function.
  • Augmented assignments such as += also count as assignments.
  • Changing the contents of a mutable global object is different from rebinding the global name.
  • nonlocal updates a variable from the nearest enclosing function scope.
  • A nonlocal variable must already exist in an enclosing function.
  • if, for, and while statements do not create separate local scopes.
  • List comprehensions keep their iteration variables inside the comprehension scope.
  • A Python global variable belongs to the current module rather than automatically to the complete application.
  • Parameters and return values are often clearer than shared global state when a function does not need persistent shared data.

Practice Python Variable Scope in Google Colab 🔝

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 Colab

Want to view the source notebook? View it on GitHub.


Functions All Built in Functions in Python


Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
©2000-2026   plus2net.com   All rights reserved worldwide Privacy Policy Disclaimer