July 16, 2026 · 3 min read
PythonInternalsFrom Script to Screen: How Your Code Actually Runs
This is Part 3 of a three-part series on Python internals (Part 1 · Part 2). Based on CPython 3.9.
You've written your script and pressed Enter. Initialization (Part 2) is done — the engine is awake. What happens next? Your code goes on a journey from a text file to a living, breathing program, in three steps.
Step 1: Choosing a path
Python first looks at how you started it. There are several entry modes, and each takes a slightly different route into the engine:
- A script file:
python app.py - A single command:
python -c "print('hi')" - A module:
python -m http.server - The interactive REPL: just
python, where each line you type goes through the whole pipeline below, one statement at a time
It also checks what you've given it. If there's a matching pre-compiled .pyc file (cached in __pycache__/ and still fresh), Python can skip the compilation step entirely and jump straight to execution — that's the whole point of those files. Free startup time, no behaviour change.
Step 2: The transformation (compilation)
If you're running a standard .py file, Python can't execute your text directly. The compiler in Python/ transforms it — text to parse tree, tree to bytecode: a simplified instruction language that's much easier for the engine to process than human-shaped source code.
The result is packaged into a Code Object — a recipe for your program. It holds the bytecode itself, the names and constants it references, and metadata like how much stack space it needs. You can actually hold this recipe in your hands:
def greet(name):
return f"Hello, {name}"
import dis
dis.dis(greet) # human-readable bytecode
print(greet.__code__) # the code object itself
Run that and you're looking at the exact instructions the engine will execute — no magic left, just a list of small steps.
Step 3: The frame and the loop
A recipe isn't a meal. To run the code object, Python creates a Frame Object — a workspace that holds your local variables, a value stack for intermediate results, and a pointer to which instruction is next. Every function call gets its own frame; the call stack you see in a traceback is literally a chain of these frames.
Then Python enters the Evaluation Loop — the heart of the entire interpreter, living in Python/ceval.c. It's a single, massive loop of almost 3,000 lines of C code: fetch the next bytecode instruction, jump to the code that handles it, execute, repeat. Millions of times per second, until your program is finished.
That's the whole trick. Every Python program you've ever run — web servers, ML pipelines, one-line scripts — reduces to this loop reading small instructions off a recipe, one at a time.
The journey, end to end
your .py file
→ compiler → bytecode → Code Object (the recipe)
→ Frame Object (the workspace)
→ Evaluation Loop in ceval.c (the engine)
→ your output on screen
Once you've seen the pipeline, Python stops being a magic box. It's a compiler, a recipe, a workspace, and a very fast loop — built by people, readable by you. If this series made you curious, the CPython source is free, and Objects/, Lib/, and Python/ (Part 1) are waiting.