Phase 1 of 25 · Topic 1.4

PyCodeObject & PyFrameObject Memory Layout

1Concept

When a Python function is executed, CPython creates a `PyFrameObject` holding local variables (`f_localsplus`), value stack (`f_valuestack`), and execution pointer (`f_lasti`) pointing into the read-only `PyCodeObject` (`co_code`).

2Architecture Diagram

[ PyCodeObject (Read-only immutable bytecode) ]
       ^
       | Referenced by
[ PyFrameObject (Dynamic call frame created per invocation) ]
  +-------------------------------------------------------+
  | f_back (Pointer to parent caller frame)               |
  | f_localsplus (Fast local variable array)              |
  | f_valuestack (Evaluation operand stack)               |
  +-------------------------------------------------------+

3Code Example

Python 3.12
import inspect

def inner_function():
    frame = inspect.currentframe()
    print("=== Execution Call Frame Diagnostics ===")
    print(f"Current Function: {frame.f_code.co_name}")
    print(f"Caller Function: {frame.f_back.f_code.co_name}")
    print(f"Local Variables: {frame.f_locals}")

def outer_function():
    user = "Senior Engineer"
    inner_function()

outer_function()

4Expected Output

=== Execution Call Frame Diagnostics ===
Current Function: inner_function
Caller Function: outer_function
Local Variables: {}

5Key Takeaways

  • PyCodeObject contains bytecode instructions and is cached in memory.
  • PyFrameObject represents active function execution and is destroyed when function returns.
  • Recursion limit in Python prevents stack frame exhaustion (`sys.getrecursionlimit()`).