NumPy·Lesson 1·8 min·0/3 exercises

What an ndarray actually is

One type, one block of memory — and why everything else follows from that.

np.array.shape.ndim.dtype.itemsize.nbytes

Watch it happen

Play it through, or step back and forth yourself.

a
0
1
2
3
4
5
6
7
8
9
10
11
  • a.shape(3, 4)
    size along each axis
  • a.ndim2
    how many axes
  • a.dtypeint64
    one type, whole array
  • a.itemsize8 bytes
    every element, identical
  • a.nbytes96 bytes
    12 x 8, contiguous

This is an ndarray: a grid of numbers, all the same type, laid out in one unbroken block of memory. It looks like a list of lists. It is nothing like a list of lists.

The idea

A NumPy array looks like a list of lists, and that resemblance is the source of most early confusion. They are built on completely different ideas.

A Python list is a row of pointers. Each one points off to a separate object living somewhere else in memory, and those objects can be anything — an int, a string, another list. Flexible, and slow: reading ten million values means following ten million pointers.

An ndarray is one unbroken block of memory holding values of a single type. No pointers, no per-element objects. Element [2][1] isn't looked up, it's calculated — start address, plus offset, done.

Hand-drawn notes contrasting a Python list, drawn as four boxes with arrows pointing away to scattered objects, with an ndarray drawn as one unbroken bar of twelve equal cells.

Shape and axes

a.shape is a tuple with one entry per axis. For (3, 4): axis 0 has length 3, axis 1 has length 4. It's tempting to translate that to "3 rows, 4 columns", and for 2-D that's harmless — but the habit breaks the moment you meet a 3-D array, and every image you ever load will be 3-D. Learn to say "axis 0" now and save yourself the retraining.

a.ndim is just len(a.shape). a.size is the product — the total number of elements.

Hand-drawn notes showing a 3 by 4 grid with axis 0 labelled down the side and axis 1 along the top, and the shape, ndim and size values written beside it.

One dtype for the whole array

Every element shares one type, fixed when the array is created. This isn't a restriction bolted on, it's the thing that makes the contiguous block possible: uniform type means uniform size means calculable addresses.

The consequence catches people out. Put a float into an int array and NumPy doesn't widen that one element — it has nowhere to put it. Depending on how you do it, either the value is truncated, or the whole array is rebuilt as float:

a = np.array([1, 2, 3])       # dtype int64
a[0] = 9.7                    # truncated to 9 — no warning
np.array([1, 2, 3.5])         # dtype float64 — the whole array
Hand-drawn notes showing one dtype governing a whole array: identical fixed-width boxes, with 9.7 being truncated to 9 on assignment, and a float in the constructor promoting the entire array to float64.

And mix in a string and everything becomes a string. If an array's dtype ever surprises you, check what you fed the constructor.

Practice

Write it yourself. The answer is there when you want it.

Putting the kettle on…

Starting up…

Write it yourself

not graded

Print a, then its shape, ndim, size and itemsize — each with a label so you can tell them apart. Finish with a.dtype on a line of its own, so it comes back as the result.

Write something and press Run — the output appears here.

Your turn

3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Return the shape of cups.

your answer

Build an array from [1, 2, 3] forced to float64, then return its dtype to prove it worked.

your answer

How many bytes does a take up in total? Return the number.

your answer