Intuition The ONE core idea
range() is a rule for producing evenly-spaced whole numbers on demand — you say where to start , where to stop , and how big each step is. To truly understand it you only need three ideas: what a whole number line looks like , what "evenly spaced" (a step) means , and what "stop before the wall" (a half-open interval) means — everything else is built from these.
Before we can read a single line like range(2, 9, 2), we must earn every mark on the page. Below, each symbol is given plain words, a picture, and the reason the topic cannot live without it. They are ordered so each one leans only on the ones above it.
An integer is a whole number with no fractional part: … , − 3 , − 2 , − 1 , 0 , 1 , 2 , 3 , … . No halves, no decimals.
Picture a ruler that stretches forever in both directions. Every tick is one integer. Zero sits in the middle; positives go right, negatives go left.
Intuition Why the topic needs this
range() produces integers only — never 2.5 , never π . That single fact explains one of the parent note's mistakes: range(0, 1, 0.1) fails because 0.1 is not an integer. So the number line above is literally the raw material range() hands out, tick by tick.
Question: Can range() ever output 3.5 ? No — it deals only in integers (whole ticks).
Definition Step (the jump size)
A step is a fixed distance you move each time along the number line. Step + 2 means "hop two ticks to the right". Step − 2 means "hop two ticks to the left".
Look at the arrows below. Every arrow is exactly the same length — that "same length every time" is what evenly spaced means, and it is the whole personality of a range.
Intuition Why direction matters
The sign of the step tells you which way to hop. A positive step walks right (numbers get bigger); a negative step walks left (numbers get smaller). This is exactly why the parent note's range(10, 0) gives nothing: with a positive default step you would try to walk right from 10, but 0 is to the left — you can never arrive.
This connects to Arithmetic sequences : a list where each term differs from the last by a fixed amount is called an arithmetic sequence, and a range is precisely a discrete arithmetic sequence made of integers.
Question: What does a negative step do on the number line? Hops leftward, so the numbers decrease.
Now we can decode the parent note's central formula. Let us earn each symbol.
Definition The symbols in
a k = start + k ⋅ step
a means "a term" — one of the numbers produced.
k (read "kay") is the position counter : which term we are asking for. It starts at 0 : the first term is a 0 , the second is a 1 , and so on.
a k (read "a-sub-k") means "the term at position k " — the subscript is just a label pointing at a spot in the list, not multiplication.
⋅ is a multiplication dot; k ⋅ step means "k copies of the step".
Let's read it on a picture. Take start = 2, step = 2:
a 0 = 2 + 0 ⋅ 2 = 2 — zero hops, still standing on the start.
a 1 = 2 + 1 ⋅ 2 = 4 — one hop.
a 2 = 2 + 2 ⋅ 2 = 6 — two hops.
Intuition Why start counting
k at 0
Because "k hops from the start" must give the start itself when k = 0 . This is the same reason Indexing and slicing in Python starts at position 0 — the first element is "zero steps in". Aligning range with this convention means loop indices line up perfectly with list positions.
a k means a times k ."
Why it feels right: letters next to letters usually mean multiply. The truth: the lowered k is a subscript — a name tag for a position, not a factor. a 3 is "the 4th term", not "a times 3".
Question: In a k = start + k ⋅ step , what does the subscript k mean? The position of the term (0 = first, 1 = second, ...), not multiplication.
Definition Interval notation
[ start , stop )
This is a way to name a stretch of the number line and say exactly which ends are inside.
A square bracket [ means the endpoint is included .
A round bracket ) means the endpoint is excluded .
So [ 2 , 9 ) means "from 2 (included) up to but not reaching 9".
Picture a fence with a solid dot on the left end (you stand there) and a hollow dot on the right end (a wall you must not touch).
range is half-open, not closed
This one design choice buys a beautiful guarantee: len(range(n)) == n, always. If both ends were included you'd forever be adding or subtracting one in your head. By excluding stop, range(5) gives exactly 5 numbers ( 0 , 1 , 2 , 3 , 4 ) — no off-by-one arithmetic. This is the same half-open rule Indexing and slicing uses, so the two ideas reinforce each other.
Question: What does the round bracket in [ 2 , 9 ) tell you? 9 is excluded — you stop before it.
Definition The comparison symbols
a k < stop reads "the term is less than stop" — it hasn't reached the wall yet (used when walking right).
a k > stop reads "the term is greater than stop" — still above the floor (used when walking left).
The parent note says: keep producing terms while they are still valid . "Valid" depends on which way you walk:
Step direction
Keep going while
Picture
step > 0 (rightward)
a k < stop
approaching wall from the left
step < 0 (leftward)
a k > stop
approaching floor from the right
Intuition Why the test must flip
When walking right, "not yet at the wall" means "smaller than stop". When walking left, the wall is now below you, so "not yet there" means "bigger than stop". Same idea — "haven't crossed the boundary" — mirrored. This is exactly why range(10, 0, -2) excludes 0: with a leftward step the test is a k > 0 , and the term 0 fails 0 > 0 .
Question: With a negative step, what comparison decides whether a term is included? a k > stop (greater than).
The parent's count formula n = max ( 0 , ⌈ step stop − start ⌉ ) uses two new symbols.
⌈ x ⌉
⌈ x ⌉ (read "ceiling of x ") is x rounded UP to the nearest integer. ⌈ 3.5 ⌉ = 4 , ⌈ 3 ⌉ = 3 , ⌈ 3.01 ⌉ = 4 . The little brackets look like the top corners of a box — a hint that you push up to the ceiling.
max ( a , b )
max ( a , b ) just picks the larger of two values. max ( 0 , − 3 ) = 0 ; max ( 0 , 4 ) = 4 .
Intuition Why each piece is there
The fraction step stop − start is "total distance to cover ÷ size of each hop" = how many hops fit .
We round up with ⌈ ⌉ because even a partial leftover distance still means one more term exists on the near side of the wall.
We wrap in max ( 0 , … ) because if you're walking the wrong way , the fraction goes negative — and you can't have a negative count of numbers, so we clamp to 0. That's the machinery behind the empty range(5, 1).
Question: Why is max ( 0 , … ) needed in the count formula? To turn a negative (wrong-direction) result into 0 — you can't have negative elements.
Lazy means Python does not build the whole list of numbers up front. It stores only the rule (start, stop, step) and computes the next number the instant you ask. Picture a vending machine that makes each snack on order, not a warehouse pre-stocked with a million snacks.
Immutable means "cannot be changed after it is made". A range object is a fixed recipe; you can read from it but not edit it in place.
Intuition Why laziness matters for loops
for i in range(1000000) uses almost no memory, because the numbers are dreamed up one at a time. Contrast with Lists and list() , where list(range(1000000)) really does build all million integers. range powers for loops precisely because it feeds indices cheaply.
Question: What does "lazy" mean for a range object? It generates each number on demand instead of storing them all at once.
Integers and the number line
Term formula a_k = start + k times step
Half-open interval start included stop excluded
Comparison test less-than or greater-than
Ceiling and max for the count
Lazy and immutable sequence
Self-test: can you answer each before opening the parent note?
Is 2.5 an integer? No — integers are whole numbers only.
What does a step of − 3 do on the number line? Hops 3 ticks to the left (numbers decrease).
In a k = start + k ⋅ step , what is a 0 ? The start itself (zero hops taken).
Is the subscript in a k multiplication? No — it labels the term's position.
Does [ 3 , 8 ) include 8? No — the round bracket excludes it.
Which test is used when the step is positive? a k < stop .
Which test is used when the step is negative? a k > stop .
What is ⌈ 3.2 ⌉ ? 4 (round up).
What is max ( 0 , − 5 ) ? 0 (the larger value).
Why does range use so little memory? It is lazy — it computes numbers on demand instead of storing them.
Parent topic — this page builds every symbol it assumes.
Arithmetic sequences — the term formula a k = start + k ⋅ step is a discrete arithmetic progression.
Indexing and slicing — same half-open convention and 0-based counting.
for loops — where these integers get consumed one at a time.
Lists and list() — the eager cousin that materialises every number.
numpy.arange / linspace — the float-capable relatives (recall: range is integers only).
enumerate() — pairs an index with a value when you need both.