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.
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()
LEGB lookup order:
len, print)Scope keywords:
global var: access/modify global scope from functionnonlocal var: access/modify enclosing scope from inner functionClosures:
Inspecting namespaces:
locals(): dict of local namespaceglobals(): dict of global namespacevars(obj): object's attribute namespace (equivalent to obj.__dict__)dir(obj): list of accessible attributesCommon mistakes:
nonlocal and thinking you're modifying enclosing variable (creates local instead)x hides global x invisiblydef f(x=[]): modifies same list on each callLate 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):