This page assumes nothing. Before you meet dtype, shape, or strides in the parent note, you need a picture of what a byte, an index, a tuple, and memory even are. We build each from zero, in the order they stack.
Why the topic needs this. Everything NumPy does is "compute an address, then read the drawers there." If drawers and addresses aren't concrete for you, the word stride (a jump measured in drawers) will float in the air with nothing to stand on. Look at the figure: the numbers under the row are addresses; the numbers inside are contents. NumPy always works with the addresses.
Notation you'll see: A[i] means "the element of A at index i." The letter i is just a stand-in for some whole number.
The figure shows the same six drawers labelled two ways: the black numbers are true addresses; the orange labels [0] [1] [2] … are the indices we choose to lay on top.
Why not just call it a list? Because in Python a list can grow and shrink; a tuple is meant to be a small, unchanging label. shape and strides are both tuples — one number per direction.
If you've met vectors as (x, y) pairs, a tuple is the same idea, just possibly longer.
Why the topic needs it. An array can have 2, 3, 4, or more directions (called axes). We can't invent a fresh letter for each, so we write d0,d1,d2,… and let k roam over the axis numbers. When you see ik it means "the index we chose along axis k."
The parent note writes the total number of elements as ∏kdk and the byte offset as ∑kik⋅stridek. These two Greek capitals are just shorthand for repeated arithmetic.
Why these tools and not just writing it out? Because an array can have any number of axes. Writing i0stride0+i1stride1+i2stride2+… forever is impossible; ∑ says "do this for every axis, however many there are" in one symbol. It answers the question "how do I state one rule that works for 2-D, 3-D, and 100-D at once?"
The figure shows ∑ as a set of arrows all flowing into one "+" box, and ∏ as arrows flowing into one "×" box — the symbol is just the funnel.
Why the topic needs it. NumPy is fast because array data is usually one contiguous buffer: the CPU can read neighbours cheaply (this is the deep reason behind CPU cache & memory locality). The whole trick of strides is possible only when NumPy controls exactly how far apart consecutive logical elements sit in the buffer — and that spacing is measured against a contiguous baseline.
Here is the concept that makes strides inevitable. A grid (rows and columns) must be flattened into the single line of memory. There is a choice about the order.
Why the topic needs it. Once you see the grid unrolled row by row (the figure's orange path), the flat position of A[i, j] is obvious: to reach row i you must pass i whole rows of length C, then step j more. That is literally i⋅C+j — the formula the parent derives. The picture is the derivation. (The opposite choice, column-major, is Row-major vs column-major (C vs Fortran order).)
Why the topic needs it. If cell 0 were 8 bytes but cell 1 were 2 bytes, "jump one step" would have no fixed size and strides couldn't exist. Homogeneity is precisely what lets a single itemsize describe "how fat is each cell," and lets stride jumps be constant.