Python Under the Hood
Cpython consists of many things:
CPython executable
├── parser
├── compiler: source code -> bytecode
├── bytecode interpreter / VM: runs bytecode
└── runtime: objects, memory, imports, exceptions, GC, etc.
When we run our python program,
your .py file
↓
[compiler part of Python]
↓
bytecode
↓
[Python virtual machine / runtime]
↓
executes bytecode- Python Bytecode is not machine code, it’s instructions for the Python interpreter.
What happens when in my python file / REPL I import other files?
Like as soon as I import, does that python program with all its defined functions get compiled to bytecode?
- Yes, the function bodies are compiled, but not run yet
Python Errors
Errors happen at either:
- compile time
- execution time
Most other errors happen at runtime.
syntax/indentation errors → compile time
name/type/value errors → execution timeCompile-Time Errors
Caught before anything runs. Usually syntax/indentation errors.
x =
# SyntaxErrordef f():
print("hi")
IndentationError
Execution-Time Errors
Code compiles, then fails while running.
print("before")
x = 1 / 0
print("after")Output:
before
ZeroDivisionErrorCommon runtime errors:
NameError
TypeError
ValueError
ZeroDivisionError
IndexError
KeyError
AttributeErrorPython footgun
Python footgun: top-level imports run immediately
In Python,
import moduleexecutes all top-level code in that module once.So a global import can crash your program even if you never call the code that uses it.
# renderer.py
import pango # runs immediately when renderer.py is imported
def render_text():
...# main.py
import renderer # can fail here because pango import runs nowBetter:
# renderer.py
def render_text():
import pango # only required when this function is called
...Key idea:
Top-level import = dependency required to load the whole module.
Local import = dependency required only for that specific code path.