Question presented to candidate:
"When I type python app.py, what actually happens between the text in that file and the program running? Is Python compiled or interpreted, what are bytecode and .pyc files, and what changed in CPython 3.11 to make it faster?"
What a strong answer should cover:
- The pipeline: the tokenizer turns text into tokens, the parser builds an AST, the compiler turns the AST into a code object holding bytecode, and the interpreter's eval loop runs that bytecode
- Python is "compiled to bytecode, then interpreted": the whole file is compiled first, so a
SyntaxErroranywhere stops even line 1, while aNameErroronly appears when that line runs - The eval loop is a stack machine: instructions such as
LOAD_FAST,BINARY_OP,STORE_FASTpush and pop a value stack inside a per-call frame;disshows them - Imported modules cache bytecode in
__pycache__/name.cpython-311.pyc(16-byte header, then a marshalled code object); the script you run directly is not cached, and a.pyconly skips compiling, it does not make code run faster - Bytecode is a CPython implementation detail that changes between versions (different instructions in 3.11, 3.12 and 3.13 for the same function)
- 3.11's specializing adaptive interpreter (PEP 659) rewrites hot instructions into type-specific ones such as
BINARY_OP_ADD_INT; an experimental JIT followed in 3.13 (PEP 744)
Code / implementation expected: Optional โ reading dis output for a small function and explaining each instruction is the usual exercise.