learn
Weeks 1–3 · About 30 hours

Telling the computer what to do

Storing information, making decisions, and repeating work. These three ideas sit underneath every program ever written.

Every algorithm later in this roadmap is loops and decisions underneath the surface. — one of the most famous there is — turns out to be a loop with two variables in it. If loops are still effortful for you, binary search will feel impossible. If loops are automatic, it will feel obvious. That difference is decided here.

Variables and types

A variable is a name your program uses to find a value again.

Reach for it whenUse a variable instead of repeating a literal when the value has meaning, changes, or is reused; keep a literal when naming it would add no clarity.

Think of it likeA luggage tag. The tag is not the suitcase; it just lets you refer to the suitcase without carrying it around.

You write price = 20, and from then on the name price refers to the number 20. Later you can write price = 25 and the name refers to something else. Nothing is permanent.

There are four kinds of information you meet immediately. Whole numbers, called integers — 3, 100, -7. Numbers with a decimal point, called floats — 3.5, 0.001. Text, called strings, always written inside quotes — "hello". And true-or-false values, called booleans — written True and False, capitalised.

Syntax you can use
count = 3
Binds the name count to the value 3. No type declaration needed.
name, age = "Ada", 36
Assigns several names at once, left to right.
count += 1
Shorthand for count = count + 1. Also -=, *=, /=.
type(count)
Tells you what kind of value a name currently holds.
total = None
The “nothing yet” value, for a name that exists but has no answer.Test it with `if total is None:`, never == None.
MAX_TRIES = 5
A constant by convention. Capitals tell a reader not to reassign it; Python will not stop you.
alistbsame[1,2]
Notice that two names can lead to one mutable value; assignment copies a reference, not the list itself.
Several ways to see it
Its shapeA name points at a value; it is not the box

Draw the name on the left and an arrow to an object on the right. Assignment can swing that arrow toward a different object, and two names can point to the same mutable object.

What the machine doesAn operation asks the value what it supports

When Python evaluates `a + b`, it inspects the objects bound to those names and dispatches type-specific behaviour. That is why the same symbol adds numbers, joins strings, and rejects incompatible pairs.

How it breaksShared mutation makes the arrow model matter

If two variables refer to one list, changing it through either name changes the same list. Reassignment only moves one name, so confusing mutation with reassignment creates bugs that look like action at a distance.

In the wild
  • CPython — binds names in local, global, and built-in namespaces to Python objects.
  • Jupyter Notebook — keeps names and their values in the live kernel between executed cells.
Commonly gets misread as
  • "A variable is a box containing the object." Correction: in Python it is a name bound to an object.
  • "The type belongs permanently to the name." Correction: the same name can later refer to a different kind of value.

Getting information in and out

Input crosses into a program; output is what the program sends back out.

Reach for it whenUse standard input and output instead of a GUI or web API for small tools and pipelines; choose a structured API when other software needs reliable fields and errors.

print("hello") puts hello on the screen. That is your main window into what your program is doing, and for the next few weeks it is also your main debugging tool — when something is wrong, print the value and look at it.

name = input("What is your name? ") shows the question, waits for typing, and stores whatever came back in name. One trap catches everyone: input() always gives you text, even when the person typed a number. If you need the number 5 rather than the text "5", you have to convert it with int().

Syntax you can use
answer = input("Your name: ")
Prints the prompt, waits, and returns what was typed.
age = int(input("Age: "))
Converts the typed text into a whole number.input ALWAYS returns a string. "3" + 1 is an error; int("3") + 1 is 4.
print(f"{name} is {age}")
An f-string: anything inside the braces is evaluated and inserted.
print(f"{price:.2f}")
Formats a number to two decimal places.
print(a, b, sep=", ")
Prints several values with a separator you choose.
print("loading", end="")
Prints without starting a new line.
Several ways to see it
What the machine doesInput crosses into Python as text

`input()` waits for a line from standard input, removes the final newline, and returns a string. Converting to `int` is a separate operation that can fail, which is why validation belongs at the boundary.

Against the alternativeReturning data keeps logic reusable

Printing is for a person or a log; returning gives a value back to another part of the program. A function that returns a total can be tested and reused, while one that only prints has thrown the result away.

The Python you typeFormatted strings keep the template visible

An f-string places expressions beside the words they fill: `f"Total: {total:.2f}"`. It is easier to audit than a chain of conversions and `+` operators, especially when formatting numbers.

In the wild
  • Unix pipelines — connect one process's standard output directly to the next process's standard input.
  • Docker — collects a container process's standard output and error streams as logs.
Commonly gets misread as
  • "print returns a value to the caller." Correction: it writes text; return passes a value between functions.
  • "input gives you a number when digits are typed." Correction: Python input returns text until you convert it.

Operators — doing things to values

An operator is a compact instruction that combines, compares, or changes values.

Reach for it whenUse an operator when its built-in meaning is clear; use a named function instead when the rule needs explanation or has several steps.

Arithmetic is what you expect: + - * / for add, subtract, multiply and divide. Two are less obvious and both matter enormously later. Double slash divides and throws away the remainder, so 7 // 2 is 3. And percent gives you only the remainder, so 7 % 2 is 1.

That percent operator looks like a novelty and is not. It is how you test whether a number is even, how clock arithmetic works, and — in week 18 — how a decides which storage slot to put something in. It shows up constantly.

Syntax you can use
7 / 2
True division. Gives 3.5, a float, even when both sides are whole.
7 // 2
Floor division. Gives 3, discarding the remainder.
7 % 2
Remainder. Gives 1, and n % 2 == 0 is the standard even test.
2 ** 10
Power. Two to the tenth.
a == b
Compares values. Also !=, <, >, <=, >=.One = assigns, two == compares. Mixing them up is the classic first bug.
x > 0 and y > 0
Both must hold. Also or for either, not to invert.
"a" in word
Membership. Works on strings, lists, sets, and dictionary keys.
0 < x < 10
A chained comparison, meaning both at once. It reads exactly like the maths.
Several ways to see it
What the machine doesPrecedence decides the tree before evaluation begins

Python groups multiplication before addition and comparisons before boolean `and` or `or`. Parentheses do more than reassure the reader: they explicitly change that evaluation tree.

How it breaksDivision creates a different kind of number

`/` produces a float even when the answer is whole, while `//` rounds downward rather than merely removing decimals. Negative inputs expose the difference: `-3 // 2` is `-2`, not `-1`.

The Python you typeChained comparisons say the interval once

Python lets `0 <= score < 100` read like the mathematics it represents. Repeating the middle value with `and` is noisier and creates another place to mistype it.

In the wild
  • NumPy — applies arithmetic operators across whole through vectorized operations.
  • PostgreSQL — evaluates comparison, arithmetic, and JSON operators inside SQL expressions.
Commonly gets misread as
  • "= compares two values." Correction: = assigns; == asks whether values are equal.
  • "and and or always return booleans." Correction: Python returns one of the operands after testing truthiness.

Conditionals — making decisions

A conditional lets the program choose which work happens after asking a yes-or-no question.

Reach for it whenUse a conditional instead of duplicating whole functions when behavior differs by a small rule; use separate strategy objects when branches keep multiplying.

Think of it likeA flowchart. You arrive at a diamond, answer the question, and take one of the paths out.

The shape is: if age >= 18: followed by an indented block of steps. If the condition is false those steps are skipped entirely, as though they were not written.

elif lets you chain more questions, and Python checks them top to bottom, stopping at the first one that is true. else is the fallback with no condition attached. You can have as many elif branches as you like, and at most one else.

Syntax you can use
if x > 0:
Runs the indented block below only when the test is true.
elif x == 0:
Checked only when every test above it failed. Use as many as you like.
else:
Runs when nothing above matched. At most one, and it takes no test.
if items:
Truthiness. An empty list, an empty string, 0 and None are all false.
label = "odd" if n % 2 else "even"
A conditional expression, for when a whole if-block would be four lines of noise.
if value is None:
An identity test, and the correct way to check for None.is asks “the same object?”, == asks “the same value?”. Use is only for None, True and False.
yesnoyesnox < 0negx == 0zeropos
Notice that the first true test ends an if/elif chain; later conditions are never consulted.
Several ways to see it
Its shapeOnly one branch of a chain can run

Lay an `if`/`elif`/`else` chain out as a fork: Python tests from top to bottom and takes the first true path. Separate `if` statements are separate forks, so several of them may run.

What it costsOrder cheap rejection before expensive proof

Boolean expressions short-circuit from left to right. Put a quick guard such as `item is not None` before an attribute lookup or costly function call, and Python may avoid that work entirely.

How it breaksTruthiness can merge cases you meant to separate

Zero, an empty string, and `None` all count as false, but they often mean different things. Test `is None` when absence is the question; otherwise a legitimate zero may take the missing-data branch.

In the wild
  • GitHub Actions — uses if expressions to decide whether a workflow step or job should run.
  • Django — checks authentication and permissions before allowing a request to reach protected behavior.
Commonly gets misread as
  • "Every if needs an else." Correction: omit else when no work is needed for the false case.
  • "Several if statements equal if/elif." Correction: separate if statements can all run; an if/elif chain chooses at most one branch.

Loops — repeating work

A loop tells the program to repeat a piece of work while changing what it is looking at.

Reach for it whenUse a for loop instead of copying a statement for each item; use a while loop when stopping depends on a condition rather than a known collection.

for item in things: runs the indented block once per item, with item referring to a different one each time. for i in range(5): runs it five times with i counting 0, 1, 2, 3, 4. Note that it starts at 0 and stops before 5 — that is deliberate, and it matches how positions in a list are numbered.

while condition: keeps going as long as the condition is true. It checks before each pass, so if the condition is already false, the block never runs at all. The risk with while is the infinite loop: if nothing inside ever makes the condition false, your program hangs forever. Press Ctrl+C in the terminal to stop it.

Syntax you can use
for item in items:
Visits each element in turn. No index arithmetic needed.
for i in range(5):
Counts 0, 1, 2, 3, 4. The end is excluded.
for i in range(2, 10, 2):
Start, stop, step: 2, 4, 6, 8.
for i, item in enumerate(items):
Gives you the position and the value together.
for a, b in zip(xs, ys):
Walks two sequences side by side, stopping at the shorter one.
while not done:
Repeats while a condition holds. Use it when you cannot say in advance how many times.
break
Leaves the loop immediately.
continue
Skips to the next iteration without finishing this one.
Several ways to see it
Against the alternativeFor consumes a collection; while waits for a condition

A `for` loop asks an iterable for successive values and stops when it is exhausted. A `while` loop rechecks a condition, so you must make some state move toward false yourself.

What the machine doesThe loop variable is rebound on every turn

Python asks the iterator for one next value, assigns that value to the loop name, then runs the body. The name survives after the loop, but changing the name does not rewrite the original collection.

How it breaksMutation can move the floor under the iterator

Adding to or removing from a list while walking it shifts positions the loop has not visited. Iterate over a copy or build a new list when membership must change.

In the wild
  • Python asyncio event loop — repeatedly takes ready callbacks and coroutines and gives them time to run.
  • Airflow scheduler — repeatedly examines workflow state and queues task instances whose dependencies are satisfied.
Commonly gets misread as
  • "A loop makes repeated work happen at once." Correction: an ordinary loop runs iterations one after another.
  • "while True is always a bug." Correction: long-running services use it deliberately, with waits and controlled exits.

What it costsA loop over n items is O(n) — the time grows in step with how many items there are. Put a loop inside another loop and you get O(n²), which gets slow alarmingly fast.

Indentation is not decoration

Indentation draws the boundary around the statements controlled by a function, loop, or decision.

Reach for it whenUse one consistent four-space level for each Python block instead of braces or visual alignment; do not mix tabs and spaces.

Most languages use curly brackets to mark where a block starts and ends. Python uses indentation instead — normally four spaces. Lines indented to the same depth belong to the same block.

This means a line indented one level too far quietly becomes part of the loop above it and runs many times instead of once. That is not a crash, it is wrong behaviour, which is harder to spot.

Syntax you can use
if x: do_something()
Four spaces mark the body. The indentation IS the block — there are no braces.
pass
A block that does nothing, for when the syntax demands a body you have not written yet.
total = (first + second)
Brackets let one expression span lines, and indentation inside them is free.
Several ways to see it
Its shapeWhitespace draws the program's ownership tree

Lines at the same indentation belong to the same block; a deeper line belongs to the statement above it. The left edge therefore records which work is inside a loop, branch, function, or class.

What the machine doesDedenting is a real instruction boundary

The parser emits indent and dedent tokens from changes in leading whitespace. Moving a line left can make it run once after a loop instead of once per iteration even though every word stays unchanged.

How it breaksTabs make equal-looking columns disagree

Editors may display a tab at different widths, while Python must interpret it precisely. Four spaces per level avoids invisible mixtures and lets formatters preserve one unambiguous structure.

In the wild
  • CPython tokenizer — turns changes in leading whitespace into INDENT and DEDENT tokens that define blocks.
  • Ruff formatter — rewrites Python layout with consistent indentation while preserving block structure.
Commonly gets misread as
  • "Indentation is only style." Correction: in Python it changes which block a statement belongs to.
  • "Any number of spaces is fine inside one block." Correction: statements at the same level must line up.

Reading about this stage is not the same as finishing it. Type every one of these from a blank file rather than copying — the writing is the part that teaches.

Temperature converter

Ask for a temperature in Celsius and print it in Fahrenheit. Then extend it to convert both ways. Exercises input, converting text to a number, arithmetic and printing.

FizzBuzz

Print the numbers 1 to 100, except: for multiples of 3 print Fizz, for multiples of 5 print Buzz, and for multiples of both print FizzBuzz. The classic first test of loops, conditionals and the remainder operator together. Order your conditions carefully — check for both before checking for either.

Number-guessing game

The program picks a secret number, the player guesses, and it replies higher or lower until they get it. Uses a while loop that keeps going until a condition is met. When you reach binary search in week 30, notice that the best guessing strategy is exactly that algorithm.

Multiplication table printer

Print a 12 by 12 times table as a neat grid. Needs a loop inside a loop — the outer one for rows, the inner one for columns. Your first taste of why nested loops are expensive.

Looping calculator

Ask for two numbers and an operation, print the result, then ask again — repeating until the user types quit. Combines input, conditionals and a while loop. Handle division by zero rather than letting it crash.

Exit checkYou can write FizzBuzz in a blank file, from memory, with no errors, in under five minutes. Not from a tutorial — from nothing.

If you cannot do this, repeat the stage rather than moving on. Nothing later gets easier by skipping it.

Worth knowing before you start

  • Type every example yourself rather than copying and pasting. The gap between understanding a video and writing code on a blank screen is the entire skill, and copying skips exactly the part that builds it.

This stage corresponds to Phase 0 — Core Syntax & Control Flow in the source roadmap.