python icon

Scoping: The LEGB Rule

Expert Answer & Key Takeaways

Mastering Scoping: The LEGB Rule is essential for high-fidelity technical performance and advanced exam competency in 2026.

Scoping & Namespaces: The LEGB Rule and Local/Global Internals (2026)

Python resolves variable names using the LEGB (Local, Enclosing, Global, Built-in) rule, implemented via hierarchical namespace dictionaries that determine object visibility and lifetime.

1. The Proof Code (Closure Internals)

import dis def outer_function(x: int): # Enclosing scope def inner_function(y: int): # Local scope accessing 'free variable' x return x + y return inner_function closure_func = outer_function(10) def inspect_closure() -> None: print(f"Result: {closure_func(5)}") # Inspecting the 'cell' that stores the free variable print(f"Free variables: {closure_func.__code__.co_freevars}") print(f"Cell value: {closure_func.__closure__[0].cell_contents}") if __name__ == "__main__": inspect_closure() print("\nBytecode for inner_function:") dis.dis(closure_func) # Output: # Result: 15 # Free variables: ('x',) # Cell value: 10 # Bytecode shows: LOAD_DEREF 0 (x)

2. Execution Breakdown

  1. Namespaces as Dictionaries: A namespace is literally a Python dictionary. globals() returns the dictionary for the module scope, while locals() returns the dictionary for the current function execution.
  2. Lexical Scoping: Python determines the scope of every variable at compile-time. If you assign to a name anywhere in a function, Python marks that name as 'Local' for the entire function, regardless of the assignment order.
  3. Free Variables: In a nested function, a variable that is referenced but not defined locally is a 'free variable'. Python stores these in a special __closure__ attribute to ensure they persist even after the outer function finishes.
  4. LEGB Search Order: When Python sees a name, it searches: Local -> Enclosing -> Global -> Built-in. If not found in any, it raises a NameError.

3. Detailed Theory

The efficiency of name resolution depends on which scope the variable resides in.

LOAD_FAST vs. LOAD_GLOBAL

In CPython, local variables are optimized. The compiler knows exactly how many locals a function has and stores them in a fixed-size array. Accessing them uses the LOAD_FAST opcode, which is an array index lookup (very fast). Global and Built-in lookups use LOAD_GLOBAL, which requires a dictionary hash table lookup (slower).

The UnboundLocalError Trap

Consider this common bug:
x = 10 def fail(): print(x) x = 20 # Compilation marks 'x' as local
Executing fail() raises UnboundLocalError because Python decided x was local during compilation, but at runtime, the print(x) happens before the local x has been assigned a value.

Modifying Scopes

  • global: Forces a name to be resolved in the module-level dictionary.
  • nonlocal: Forces a name to be resolved in the nearest enclosing (outer function) scope, enabling stateful closures.
[!TIP] Senior Secret: To optimize performance-critical loops that call global functions (like math.sin), bind the global function to a local variable first: sin = math.sin. This converts multiple LOAD_GLOBAL lookups into faster LOAD_FAST lookups inside the loop.

Top Interview Questions

?Interview Question

Q:What is a 'free variable' in the context of Python closures?
A:
A free variable is a variable referenced in a code block (like a nested function) that is not defined there. For a closure, these variables are captured from the enclosing scope and stored in the function's __closure__ attribute.

?Interview Question

Q:Why is local variable access faster than global variable access?
A:
Local variables are stored in a fixed-size array and accessed via index (LOAD_FAST). Global variables are stored in a dictionary and require a hash table lookup (LOAD_GLOBAL), which involves more CPU instructions.

?Interview Question

Q:What happens if you modify a 'locals()' dictionary inside a function?
A:
Modifying the dictionary returned by locals() generally has no effect on the actual local variables. Python updates this dictionary from the internal stack/array, but it does not read changes back from the dictionary into the local variables.

Course4All Engineering Team

Verified Expert

Data Science & Backend Engineers

The Python curriculum is designed by backend specialists and data engineers to cover everything from basic logic to advanced automation and API design.

Pattern: 2026 Ready
Updated: Weekly