How Python runs your code
Before writing much Python, see what happens when you run it — how source text becomes tokens, a syntax tree and bytecode that a small virtual machine executes — and learn to read the errors it gives you.
In this lecture you will
- Run Python code in the interactive shell and as a script
- Describe the stages from source code to execution in CPython
- Distinguish syntax errors from runtime exceptions
- Read a traceback and find the line that caused an error
Python is one of the most widely used programming languages in the world — for automation, web back ends, data analysis and machine learning. It is famous for being readable. This first lecture looks at what actually happens when you run it, because a clear mental model makes everything that follows easier.
Two ways to run Python
Install a recent version of Python 3, open a terminal and type python3 (on Windows, py). You are now in the interactive shell, also called the REPL — read, evaluate, print, loop. Type an expression and see the result immediately:
>>> 19.5 * 3
58.5
>>> "Euler" + "Skills"
'EulerSkills'
For real programs, write code in a file and run it as a script:
# greet.py
name = input("What is your name? ")
print(f"Hello, {name}! Welcome to Python.")
python3 greet.py
The shell is ideal for experiments; scripts are how you build tools you can rerun, share and test.
What happens when you press Enter
The standard implementation of Python, CPython, doesn’t run your text directly. It passes through a short pipeline. Scroll through it with a small program:
- 11 · Source code
You write plain text. Python reads the whole file (or the line you typed in the shell) before running anything.
- 22 · Tokens
The tokenizer breaks the text into meaningful pieces: names, operators, numbers and line ends. Spaces between tokens are dropped — but indentation at the start of a line is kept, because it marks blocks.
- 33 · Syntax tree
The parser checks the grammar and builds an abstract syntax tree (AST): an assignment whose value is a multiplication of two names. A missing bracket fails here, as a SyntaxError.
- 44 · Bytecode
The compiler turns the tree into bytecode — simple instructions for a virtual machine: load price, load qty, multiply, store total.
- 55 · The virtual machine runs it
The interpreter loop executes one instruction at a time, pushing values onto a stack and popping them off. Names and values live in memory until the program ends.
This is why Python is often called an interpreted language, even though there is a compile step: the bytecode is interpreted by the virtual machine rather than turned into native machine code.
You can watch the virtual machine work. Step through the real bytecode of two tiny programs, and notice that an if statement becomes nothing more than a conditional jump:
Bytecode from CPython 3.14, without offsets. Every Python version changes some details. To see the bytecode of your own function, run import dis and then dis.dis(your_function).
Two kinds of errors
Because parsing happens before execution, errors fall into two families.
Syntax errors are found while reading the code. Nothing runs at all:
print("Total:", total
# SyntaxError: '(' was never closed
Exceptions happen while the program is running, when an operation can’t be carried out — a name that doesn’t exist, adding text to a number, dividing by zero:
Traceback (most recent call last):
File "report.py", line 12, in <module>
summary = build_summary(orders)
File "report.py", line 7, in build_summary
return total / count
ZeroDivisionError: division by zero
Read a traceback from the bottom up. The last line says what went wrong (ZeroDivisionError: division by zero). The line above it says where (report.py, line 7). The lines above that show how the program got there — the chain of function calls.
Run five small scripts, each with one mistake, and compare what happens before the error:
Outputs are exactly what CPython 3.14 prints. A syntax error stops everything before the first line runs; an exception stops the program midway, after earlier lines have already done their work — which matters when those lines wrote files or sent messages.
- NameError
- A name was used before it was defined — often a typo.
- TypeError
- An operation was applied to the wrong type, such as "3" + 4.
- ValueError
- The type is right but the value isn’t, such as int("abc").
- IndexError / KeyError
- A list position or dictionary key doesn’t exist.
- AttributeError
- An object doesn’t have the method or field you asked for.
Is Python slow?
Executing bytecode one instruction at a time costs speed — pure-Python loops can be tens of times slower than equivalent code in C or Java. In practice this matters less than you might think:
- most business scripts spend their time waiting — for files, networks and databases — not calculating;
- performance-critical libraries such as NumPy, pandas and PyTorch are written in C, C++ or CUDA, and Python just orchestrates them;
- recent Python versions have made the interpreter significantly faster, and work continues.
Next, we look at the most fundamental idea in Python’s model of the world: names, objects and the difference between them.
Key takeaways
- CPython parses your source into a syntax tree, compiles it to bytecode, and runs that bytecode on a stack-based virtual machine.
- Syntax errors are found before any line runs; exceptions happen while the program is running.
- A traceback reads from the outermost call at the top to the failing line at the bottom — start reading at the end.
- Python trades raw speed for productivity; heavy lifting is usually delegated to fast libraries written in C.
Check your understanding
3 questions · answers explainedQ1Your script has a missing closing bracket on line 40. When does Python report the problem?
Q2What does the Python virtual machine actually execute?
Q3In a long traceback, where should you look first to find what went wrong?