Module 1 · Foundations of Programming ⏱ 18 min

The Python Execution Environment

By the end of this lesson you will be able to:
  • Describe how an interpreter turns source code into running behavior, one statement at a time
  • Explain that Python in this course runs as Pyodide - CPython compiled to WebAssembly - inside the browser sandbox
  • Read a traceback and predict how an error halts the statements that follow it

Code on its own does nothing. A file full of Python is only text until some other program reads it and carries out the instructions inside. That program is the interpreter, and the one almost everyone uses is CPython - the reference implementation the language's own developers ship.

Interpreting means reading your source top to bottom, one statement at a time, and doing exactly what each line says before moving on. The interpreter does not read ahead and plan the whole program. If the fifth line divides by zero, the run stops right there and the sixth line never executes. That fact - later lines depend on earlier ones having already run - shapes almost everything that follows in this course.

flowchart LR
  S["source.py"] --> P["Pyodide<br/>(CPython in WebAssembly)"]
  P --> B["runs in your browser"]
  style P fill:#3776ab,color:#fff
Your source goes into Pyodide (CPython compiled to WebAssembly), which runs it inside the browser.

In this course there is nothing to install. The very same CPython has been compiled into WebAssembly (WASM) - a compact, fast binary format designed to run inside a web browser. That in-browser Python is called Pyodide. When you press Run on a code cell, genuine CPython executes your code; only the sandbox is your browser tab rather than your own computer.

Because it runs locally in the tab, there is no server round-trip and no waiting in a queue. The output you see was produced moments ago by a real interpreter working through your statements - not typed ahead of time as a picture of an answer.

Source, bytecode, and the interpreter

Before it runs anything, Python quietly compiles your source into bytecode - a denser internal form the interpreter can walk quickly. You never type bytecode and rarely see it, but the step matters: it is when syntax errors surface. A missing colon or an unmatched parenthesis is caught here, before a single statement runs, which is why the error points at a line rather than at some confusing later behaviour.

A statement is an instruction that does something, like area = width * height. An expression is anything that evaluates to a value, like width * height on its own. The interpreter can evaluate an expression whenever it meets one; a statement is what asks it to act on the result.

Real Python, running in your browser via Pyodide. Press Run.
print("Hello from the browser!")
print("2 + 3 =", 2 + 3)

Top to bottom, one statement at a time

Run that cell and the two lines execute in order: the greeting prints first, then the sum. Within a single run, a name you define on an earlier line is available to every line that follows it, because the interpreter carries those values forward as it goes.

This is why order matters. area = width * height only works if width and height were already given values above it. Flip the lines around and you ask the interpreter to use two names it has not met yet - which is exactly the kind of mistake the next code cell avoids by defining things before it uses them.

flowchart TD
  A["statement 1<br/>runs first"] --> B["statement 2<br/>runs next"]
  B --> C["statement 3<br/>runs last"]
  B -. "an error here<br/>stops the run" .-> X["statement 3 never runs"]
  style A fill:#3776ab,color:#fff
  style X fill:#dc2626,color:#fff
Statements run in order; if an earlier statement raises an error, the statements after it never execute.
Each line uses names the lines above already created.
width = 4
height = 5

area = width * height
print("area:", area)

perimeter = 2 * (width + height)
print("perimeter:", perimeter)

When a statement fails

If a statement cannot be carried out - dividing by zero, using a name that was never defined, opening a file that is not there - the interpreter stops and prints a traceback. A traceback is the chain of steps that led to the failure, and the practical way to read one is bottom-up: the final line names the error in plain English, and the lines above it show where in your code it happened.

The crucial consequence is that an error halts the whole run. Every statement after the failing line is skipped, so fixing the broken line is usually what unblocks the rest. None of this is dangerous: the failure becomes text on the screen, and nothing on your machine is touched.

The loop you will use to learn

Writing working code is rarely a single shot. The rhythm is: write a small piece, press Run, read the real output, then revise and run again. Each pass teaches you what that code actually does, because the interpreter has no opinions - it reports exactly what your statements produced.

Keep the pieces small and run often. A program you run every two lines tells you where it went wrong the moment it goes wrong, instead of letting five mistakes stack up into one baffling traceback. This tight edit, Run, observe loop is how beginners and experienced engineers alike actually work.

flowchart LR
  W["write or edit code"] --> R["press Run"]
  R --> O["interpreter executes it"]
  O --> S["read the real output"]
  S -. "revise" .-> W
  style R fill:#3776ab,color:#fff
  style O fill:#1e293b,color:#fff
Learning to code is a loop: write, Run, observe the real output, revise, then Run again.
Revise a value and Run again - the output reflects the new statements.
price = 19.99
quantity = 3

subtotal = price * quantity
tax = subtotal * 0.08
total = subtotal + tax

print("subtotal:", subtotal)
print("tax:", round(tax, 2))
print("total:", round(total, 2))
Exercise

The interpreter runs whatever valid code you give it. Write add_then_double(a, b) that adds the two numbers, then doubles the total, and returns the result.

def add_then_double(a, b):
    # add a and b, then double the sum
    pass
Exercise

What does this print? The second assignment builds on the first - predict both lines before you check.

score = 10
score = score + 5
print(score)
score = score * 2
print(score)
Exercise

In this course, what lets Python run directly in your web browser with no install?

Exercise

This snippet crashes with a NameError because it tries to use score on a line that runs before the line that creates it. Reorder the two lines so the name exists before it is used.

print(score)
score = 100
Exercise

The interpreter runs one statement at a time, so the order of assignments decides what each later line sees. Write swap(a, b) that exchanges two values using a temporary variable, returning them as the tuple (b, a). Do it step by step: copy a into temp, overwrite a with b, then set b from temp, and return the pair.

def swap(a, b):
    # use a temporary variable, one step at a time
    pass

Recap

  • Source code is inert text until an interpreter runs it; CPython is Python's reference interpreter.
  • Here CPython is compiled to WebAssembly as Pyodide, so pressing Run executes real Python inside your browser - no install, no server.
  • Statements run top to bottom; a name must exist before a later line uses it, and an error halts the run.
  • When code fails, the traceback's last line states the error type; scan upward from there to locate the line that caused it.
  • Keep your runs small and frequent, so each mistake surfaces the moment it happens.

Next you will store values in variables and watch the interpreter carry them from one line to the next.

Checkpoint quiz

What is WebAssembly (WASM) in the context of running Python here?

When you press Run on a code cell in this course, what actually executes your Python?

A program has ten statements and the fourth one raises an error. What happens to statements five through ten?

Go deeper — technical resources