Understanding Global and Nonlocal Variables in Python

Introduction

When you write Python code, variables can exist in different scopes — for example, inside a function, inside another nested function, or at the top of your script (global scope).

Understanding how to define and modify global and nonlocal variables is essential for writing clean, predictable code.

Global Variables

A global variable is defined outside any function or class and can be accessed from anywhere in the file.

By default, Python treats variables assigned inside a function as local to that function.
If you want to modify a global variable inside a function, you must declare it as global.

Example: Defining and Using a Global Variable

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Global variable
counter = 0

def increment():
    global counter  # Declare that we want to use the global 'counter'
    counter += 1
    print("Inside function:", counter)

increment()
increment()

print("Outside function:", counter)

Output:

1
2
3
Inside function: 1
Inside function: 2
Outside function: 2

Without global, you’ll get an error

If you try to modify a global variable inside a function without the global keyword:

1
2
3
4
5
6
7
counter = 0

def increment():
    counter += 1  # UnboundLocalError
    print(counter)

increment()

Error:

1
UnboundLocalError: local variable 'counter' referenced before assignment

Python assumes counter is local, so it complains because there’s no prior assignment in the local scope.

Nonlocal Variables

A nonlocal variable allows you to modify a variable in the nearest enclosing scope (but not the global scope).

This is mainly used in nested functions — functions defined inside another function.

Example: Using a Nonlocal Variable

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def outer():
    x = 10

    def inner():
        nonlocal x   # Access the 'x' defined in 'outer'
        x += 5
        print("Inside inner:", x)

    inner()
    print("Inside outer:", x)

outer()

Output:

1
2
Inside inner: 15
Inside outer: 15

Here:

  • x is not global, but belongs to outer().
  • By using nonlocal, inner() modifies x from the enclosing scope.

Without nonlocal, modification fails

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def outer():
    x = 10

    def inner():
        x += 5  # UnboundLocalError
        print(x)

    inner()

outer()

You’ll get:

1
UnboundLocalError: local variable 'x' referenced before assignment

Python thinks you’re trying to assign to a new local variable x inside inner().

Comparison Table

Feature Scope Affected Used In Typical Use Case
global Module level Any function Modify global variable
nonlocal Enclosing func Nested functions Modify outer (non-global) variable

Summary

  • Variables defined inside a function are local by default.
  • Use global to modify a global variable inside a function.
  • Use nonlocal to modify a variable in an enclosing (non-global) scope.
  • Avoid overusing global — prefer returning values or using classes for cleaner design.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
x = 100

def outer():
    x = 50
    def inner():
        global x
        x += 10
        print("Inner:", x)
    inner()
    print("Outer:", x)

outer()
print("Global:", x)

Output

1
2
3
Inner: 110
Outer: 50
Global: 110

When to Define a Global Variable Outside a Function in Python

When Global Variables Are Useful

A global variable defined outside any function is useful when:

You need shared state or constants
For example, a configuration value, path, or constant that doesn’t change during execution:

1
2
BASE_URL = "https://api.nasa.gov"
VERSION = 1.0

These are global variables — and functions can read them directly.

You want several functions to access the same variable

1
2
3
4
5
6
7
8
9
counter = 0

def increment():
   global counter
   counter += 1

def reset():
   global counter
   counter = 0

Here, both functions work with the same counter defined globally.

You’re writing small scripts or prototypes

For small, single-file programs, global variables can simplify your code.

When to Avoid Global Variables

Global variables become a problem when:

  • Your codebase grows and many functions modify them — making debugging harder.
  • You lose track of where a variable is changed.
  • Functions rely on hidden state (making them less predictable and harder to reuse).

In those cases, it’s better to use:

  • Function parameters and return values, or
  • Classes to encapsulate state.

Example: Good vs. Bad Practice

Bad: Global variable modified everywhere

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
count = 0

def add():
    global count
    count += 1

def multiply():
    global count
    count *= 2

add()
multiply()
print(count)

Here, the behavior depends on the order of function calls — risky for large programs.

Better: Return values or use classes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def add(count):
    return count + 1

def multiply(count):
    return count * 2

count = 0
count = add(count)
count = multiply(count)
print(count)

or using a class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Counter:
    def __init__(self):
        self.value = 0
    def add(self):
        self.value += 1
    def multiply(self):
        self.value *= 2

counter = Counter()
counter.add()
counter.multiply()
print(counter.value)

In Summary

Situation Should you use a global variable? Alternative
Defining constants or read-only config Yes
Small scripts or one-off analyses Okay
Large applications with shared mutable state Usually no Use classes, return values, or modules
Need to share values between functions Sometimes Pass as parameters

References

Links Site
https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces Python Docs — Scopes and Namespaces
https://docs.python.org/3/reference/simple_stmts.html#the-global-statement Python Docs — global Statement Reference
https://docs.python.org/3/reference/simple_stmts.html#the-nonlocal-statement Python Docs — nonlocal Statement Reference
https://peps.python.org/pep-3104/ PEP 3104 — Access to Names in Outer Scopes (nonlocal)
https://realpython.com/python-scope-legb-rule/ Real Python — Understanding Python Scope (LEGB Rule)