#1 Fundamentals — a short history of computing, and a why, what and how of Python
2026-07-17

Peak: #29 GitHub user in Belgium
Images: Wikimedia Commons — Antikythera (CC BY-SA 3.0), Difference Engine (public domain)

Meccano differential analyser for computing atomic spectra

\(1\,E_\mathrm{h} = \dfrac{\hbar^2}{m_\mathrm{e} a_0^2} = \dfrac{e^2}{4\pi\varepsilon_0 a_0} \approx 27.2\ \mathrm{eV}\)
Images: differential analyser (Sylvain Machefert, CC BY-SA 4.0); portrait (fair use)
“The implications of the machine are so vast that we cannot conceive how they will affect our civilisation. Here you have something which is making one field of human activity 1,000 times faster. In the field of transportation, the equivalent to ACE would be the ability to travel from London to Cambridge … in five seconds as a regular thing. It is almost unimaginable.”
— Douglas Hartree, on the Automatic Computing Engine, 1946
…and yet, all the calculations that would ever be needed in this country could be done on three digital computers: one in Cambridge, one in Teddington, and one in Manchester.
— Hartree in 1951, as recalled by Lord Bowden

The Manchester “Baby” (1948)

EDSAC, Cambridge (1949)
Images: Manchester Baby replica (Logg Tandy, CC BY 4.0); EDSAC (University of Cambridge Computer Laboratory, CC BY 2.0)
The first stored-program computers - the birth of software?

The first actual computer bug (Harvard Mark II, 1947)
Image: Wikimedia Commons (public domain, US Navy)


BRLESC-I in full
Images: Wikimedia Commons — Army computers, BRLESC-I (both public domain, US Army)
In the meantime… hard disks, programming languages, operating systems, parallel computers, graphics, personal computers, networking, the Internet, the World Wide Web
Images: Wikimedia Commons — first transistor (public domain), Intel 4004 (Thomas Nguyen, CC BY-SA 4.0), Apple M1 (CC0)

LUMI, Kajaani, Finland (2022)

MareNostrum 4, Barcelona (2017)
Images: LUMI (LUMI consortium / Fade Creative); MareNostrum 4 (Gemmaribasmaspoch, CC BY-SA 4.0)

Intel 8008 (1972), die labelled
Image: Ken Shirriff, righto.com — used with attribution

Programming languages are the “simple”, human-facing interface to all this machinery.
What you write (C):
/* the max of some numbers, in C */
double *xs = malloc(5 * sizeof(double));
if (xs == NULL) /* did we even get the memory? */
exit(1);
xs[0] = 1.0; xs[1] = 4.5; xs[2] = 2.0;
xs[3] = 8.1; xs[4] = 3.0;
double largest = xs[0];
for (int i = 1; i < 5; i++)
if (xs[i] > largest)
largest = xs[i];
free(xs); /* give it back, or leak it */
Software usage on ARCHER2, the UK national supercomputer (June 2026)
Data: ARCHER2 usage data, EPCC
gcc/clang for C, gfortran/flang for Fortran, CPython/PyPy for Pythonmean() you just saw compiles to different assembly on ARM but the C doesn’t change. That’s what portable means: write to the contract, not to the machine your analysis script
Python
NumPy / compiled libraries
compiler ・ OS
assembly ・ x86, ARM
CPU ・ gates ・ transistors
electrons
0.1 + 0.2 ≠ 0.3, “why is this loop slow?”, “why won’t this install on my machine?”Everything in memory is bits — a type is a rule for reading them.
A 32-bit signed integer:
00000000 00000000 00000000 00101010
Range: \(-2^{31}\) to \(2^{31}-1\) = 2,147,483,647 — one more and it overflows:
A double is 64 bits read as \(\pm\, m \times 2^{e}\) (IEEE 754); used extensively in scientific computing.
[ 1 sign bit | 11 exponent bits | 52 fraction bits ]
==; test fabs(a - b) < tolA C variable is a locker:

Image: another Nano Banana hallucination
1 (a C int is 4 bytes; a Python int is 28)In C, you build it yourself:
In Fortran: no dictionary in the standard library at all.
A Python dict…
| Type | Literal | Notes |
|---|---|---|
bool |
True, False |
|
int |
42 |
arbitrary precision — no overflow! |
float |
6.626e-34 |
an IEEE double underneath |
str |
"NaCl" |
Unicode text |
list |
[1, 2, 3] |
mutable sequence |
tuple |
(x, y) |
immutable sequence |
dict |
{"H": 1.008} |
key → value |
set |
{2, 3, 5} |
uniqueness & membership |
None |
None |
“nothing to see here” |
class |
class Atom: ... |
user-defined objects |
Loopable, and lookup works — but one fact per element, hidden in its position
classLoops (for, while), conditionals (if, elif, else) and functions build programs
Loops (for, while), conditionals (if, elif, else) and functions build programs
Loops (for, while), conditionals (if, elif, else) and functions build programs
Loops (for, while), conditionals (if, elif, else) and functions build programs
ptable = {
"H": Element("H", 1, 1.008, "hydrogen"),
"He": Element("He", 2, 4.003, "helium"),
...
}
def is_lanthanide(symbol):
"""Is the element a lanthanide?"""
if symbol in ptable and 57 <= ptable[symbol].Z <= 71:
return True
def get_lanthanides():
"""Return a list of all lanthanides"""
lanthanides = []
for symbol in ptable:
if is_lanthanide(symbol):
lanthanides.append(ptable[symbol])
return lanthanidesand, or, notif, elif, else)for iterates over any container (lists, dicts, files, …)Loops (for, while), conditionals (if, elif, else) and functions build programs
ptable = {
"H": Element("H", 1, 1.008, "hydrogen"),
"He": Element("He", 2, 4.003, "helium"),
...
}
def is_lanthanide(symbol):
"""Is the element a lanthanide?"""
if symbol in ptable and 57 <= ptable[symbol].Z <= 71:
return True
def get_lanthanides():
"""Return a list of all lanthanides"""
lanthanides = []
for symbol in ptable:
if is_lanthanide(symbol):
lanthanides.append(ptable[symbol])
return lanthanides
la_mass_sum = sum(e.mass for e in get_lanthanides())Nearly all of it stands on one shared abstraction: the NumPy array.
Remember why arrays are fast — one contiguous block. NumPy brings that to Python:
One line of Python = one compiled loop over the whole block
Iterate one very simple map:
\[z_{n+1} = z_n^2 + c, \qquad z_0 = 0\]
for a complex number \(c\) — i.e. a point in the plane.
max_iter times and colour it by when it escaped
Pure Python:
NumPy (whole grid at once):
| Pure Python | NumPy | Numba | Fortran | |
|---|---|---|---|---|
| 1024², 100 iterations | 1.69 s | 0.3 s | 0.02 s | 0.01 s |
0.1 + 0.2, “why is this slow?”)Research Computing with Python