A strong answer
CPython compiles source code into 2-byte wordcode instructions evaluated on a per-frame value stack inside _PyEval_EvalFrameDefault (Python/ceval.c). Starting in Python 3.11 (PEP 659 Specializing Adaptive Interpreter), generic instructions like BINARY_OP, LOAD_ATTR, and CALL reserve inline cache slots right inside the bytecode array. After a generic instruction executes a few times on the same types (warmup threshold), CPython rewrites the bytecode in-place from BINARY_OP to BINARY_OP_ADD_INT (or BINARY_OP_ADD_FLOAT, BINARY_OP_ADD_UNICODE)! On every subsequent pass, BINARY_OP_ADD_INT checks a 1-instruction type guard (a->ob_type == &PyLong_Type) and jumps straight to integer addition without generic dispatch! If a caller later passes a str, the guard fails (deoptimization), increments a miss counter, and falls back to BINARY_OP_ADAPTIVE cleanly.
A specialized bytecode instruction (such as BINARY_OP_ADD_INT) produces the exact same observable result as its generic instruction whenever its inline type/version guard holds, and deoptimizes losslessly back to the generic instruction the instant an unexpected type arrives. Because the specialized opcode begins by verifying the exact precondition (PyLong_CheckExact(left) && PyLong_CheckExact(right)) before executing the fast C path and jumps to the generic fallback on any mismatch, specialization never alters Python's dynamic semantics.
PEP 659 inline caching and zero-overhead frame allocation (_PyInterpreterFrame contiguous stack) speed up pure-Python function calls, attribute lookups, and arithmetic loops by 25% to 60% in Python 3.11–3.13. In production systems (CPython's Python/bytecodes.c, dis.dis(fn, adaptive=True), and Python 3.13's experimental copy-and-patch JIT compiler all build directly on PEP 659 specialized Tier-1 instructions.), engineers monitor these exact trade-offs to keep p99 latency predictable and prevent resource exhaustion under peak load.
What the interviewer is listening for
- Traces how CPython stack-machine bytecode and PEP 659 Adaptive Specialization operates in memory step by step rather than giving a vague textbook definition.
- States the core correctness invariant and explains why edge cases do not violate it.
- Quantifies time, space, and hardware costs (Local Lookup (
LOAD_FAST), GenericLOAD_ATTR(Pre-3.11)) with concrete numbers. - Identifies real-world failure modes (Mutating a class's methods or attributes dynamically at runtime (
User.new_method = fn) after startup) and explains how production systems mitigate them.
Common mistakes
- Treating CPython stack-machine bytecode and PEP 659 Adaptive Specialization as a black box without explaining the underlying memory or state transitions.
- Ignoring worst-case tail latency or memory overhead (Reusing the same variable or parameter for multiple unrelated types (
val = '10'; val = int(val); val = [val])). - Forgetting boundary conditions and error recovery (Assuming
x: intin Python automatically compilesxto an unboxed 64-bit C integer).