Table of Contents

Python namespace

Python namespace is a mapping from names to objects. Every scope has its own namespace (global, local, built-in), and Python searches them in order using LEGB (Local, Enclosing, Global, Built-in) to find what a name refers to. Understanding scopes prevents variable shadowing bugs and clarifies how closure variables work.

Use locals() and globals() to inspect namespaces, and understand scope rules to debug mysterious variable references.

Example

This example demonstrates namespace scope and variable shadowing.

# run: python3 namespace.py
# description: namespace scope and LEGB resolution
 
x = "global"
 
def outer():
    x = "enclosing"
 
    def inner():
        x = "local"
        print(f"Inner: {x}")
        print(f"Inner locals: {list(locals().keys())}")
 
    inner()
    print(f"Outer: {x}")
 
outer()
print(f"Global: {x}")
 
# Closure and nonlocal
def counter():
    count = 0  # enclosing scope
 
    def increment():
        nonlocal count  # access enclosing scope
        count += 1
        return count
 
    def get():
        return count
 
    return increment, get
 
inc, get = counter()
print(f"\nCounter: {inc()}, {inc()}, {inc()}")
print(f"Current: {get()}")
 
# globals() and locals()
print(f"\nGlobal 'x': {globals()['x']}")
 
def show_scopes():
    y = "local var"
    print(f"Local namespace keys: {list(locals().keys())}")
    print(f"y in locals: {'y' in locals()}")
    print(f"x in globals: {'x' in globals()}")
 
show_scopes()

Common patterns

LEGB lookup order:

Scope keywords:

Closures:

Inspecting namespaces:

Common mistakes:

Late binding example (common gotcha):

funcs = []
for i in range(3):
    def f():
        return i  # captures 'i' by reference, not value
    funcs.append(f)
 
print([f() for f in funcs])  # [2, 2, 2] not [0, 1, 2]!
# Fix: capture value with default arg: def f(i=i):