TIL: Python Behind the Scenes - CPython VM, Compiler, and Object System Deep Dive
Today I learned about the comprehensive 'Python Behind the Scenes' series covering CPython's virtual machine, compiler architecture, bytecode execution, variable implementation, and object system internals.
// Simplified CPython VM structure
typedefstruct{PyObject*f_code;// Code object containing bytecode
PyObject*f_globals;// Global namespace dict
PyObject*f_locals;// Local namespace dict
PyObject**f_valuestack;// Value stack for operations
PyObject*f_trace;// Trace function for debugging
intf_stacksize;// Current stack size
}PyFrameObject;// Main evaluation loop
PyObject*PyEval_EvalFrameEx(PyFrameObject*f,intthrowflag){// The heart of Python execution
// Interprets bytecode instructions one by one
for(;;){opcode=NEXTOP();switch(opcode){caseLOAD_FAST:// Load local variable onto stack
break;caseBINARY_ADD:// Pop two values, add them, push result
break;// ... hundreds of other opcodes
}}}
// Bytecode execution example: BINARY_ADD
caseBINARY_ADD:{PyObject*right=POP();// Pop right operand
PyObject*left=TOP();// Get left operand (don't pop yet)
PyObject*sum;// Try fast path for integers
if(PyLong_CheckExact(left)&&PyLong_CheckExact(right)){sum=long_add(left,right);}else{// General case: call __add__ method
sum=PyNumber_Add(left,right);}SET_TOP(sum);// Replace left operand with result
Py_DECREF(right);// Clean up
if(sum==NULL)gotoerror;DISPATCH();// Continue to next instruction
}
// Local variable access in CPython
typedefstruct{PyObject**localsplus;// Array of local variables
intnlocals;// Number of local variables
intnfree;// Number of free variables (closures)
// ... other fields
}PyCodeObject;// Fast local variable access
#define GETLOCAL(i) (fastlocals[i])
#define SETLOCAL(i, v) (fastlocals[i] = v)
// LOAD_FAST implementation
caseLOAD_FAST:{PyObject*value=GETLOCAL(oparg);if(value==NULL){// UnboundLocalError
gotoerror;}Py_INCREF(value);PUSH(value);DISPATCH();}
defouter(x):definner():returnx# 'x' is a free variable in inner()returninner# CPython creates a 'cell' object to store 'x'# Both outer and inner reference the same cell
// Base object structure
typedefstruct_object{Py_ssize_tob_refcnt;// Reference count
struct_typeobject*ob_type;// Type information
}PyObject;// Variable-size objects
typedefstruct{PyObjectob_base;Py_ssize_tob_size;// Number of items
}PyVarObject;// Example: Integer object
typedefstruct{PyObject_HEADdigitob_digit[1];// Actual integer data
}PyLongObject;
# Understanding performance through internals# 1. Local variable access is fastest (LOAD_FAST)deffast_locals():x=10foriinrange(1000000):y=x+i# x is local, very fast# 2. Global lookups are slower (LOAD_GLOBAL) global_var=10defslower_globals():foriinrange(1000000):y=global_var+i# global_var requires dict lookup# 3. Attribute access triggers method callsclassPoint:def__init__(self,x,y):self.x=xself.y=ydefattribute_access():p=Point(1,2)foriinrange(1000000):# Each p.x triggers __getattribute__ or __getattr__y=p.x+i# 4. Built-in functions are optimizeddefbuiltin_vs_custom():# Fast: built-in sum() is implemented in Cresult1=sum(range(1000000))# Slower: Python loop with bytecode overheadresult2=0foriinrange(1000000):result2+=i
importsys# Understanding reference countingx=[1,2,3]print(sys.getrefcount(x))# Should be 2 (x + getrefcount parameter)y=x# Increment reference countprint(sys.getrefcount(x))# Should be 3dely# Decrement reference count print(sys.getrefcount(x))# Back to 2# Circular references require garbage collectorclassNode:def__init__(self,value):self.value=valueself.parent=Noneself.children=[]# Create circular referenceparent=Node("parent")child=Node("child")parent.children.append(child)child.parent=parent# Circular reference# Without GC, this would be a memory leak# CPython's cycle detector will find and clean this up