Quick Reference · JIT-compiling Python to native machine code

numba cheat sheet

Numba is a just-in-time compiler that turns a subset of Python & NumPy into fast machine code — usually by adding one decorator. Put @njit on a function; the first call infers types and compiles it through LLVM, and every call after runs at native speed. It shines on numeric, loop-heavy code, and can parallelize across cores or offload to the GPU.

setup & types @jit core compile flags parallelism ufuncs · classes · GPU gotcha most common

Distilled & cross-checked across: numba.readthedocs.io (5-minute guide · @jit reference · parallel · performance tips · CUDA) · numba.pydata.org · Lam, Pitrou & Seibert — “Numba: a LLVM-based Python JIT compiler”, LLVM-HPC 2015 · the Numba team

What happens when you call a @njit function
Python fn pure Python + NumPy + loops @njit decorate the function Type inference 1st call: read arg types → specialize Numba IR → LLVM optimize & lower → machine code Native run fast · no interpreter cached specialization ◤ flags: cache · fastmath · parallel next call, same arg types → reuse cached machine code (no recompile) can't type it? → error (nopython) SOURCE COMPILE · ONCE PER TYPE RUN · EVERY CALL
01Install & Importonce per env
0260-Second Startadd a decorator
03nopython vs object modehow it compiles
04Compilation flagstune @njit
05Parallel loops · prangeuse all cores
from numba import njit, prange

@njit(parallel=True)          # ★ split across threads
def colsum(A):
    n = A.shape[0]
    acc = 0.0
    for i in prange(n):   # ★ parallel range
        acc += A[i]        # reduction: safe
    return acc

# see what got parallelized:
colsum.parallel_diagnostics(level=4)
# nested prange → only the outer runs parallel
# writing shared A[j] across threads → race!
06Thread controlmanage the pool
07Signatures & eager compilelazy vs eager
08ufuncs · @vectorizescalar → array
09@guvectorize & @stencilarrays & neighborhoods
10jitclass & typed containersobjects that compile
11CUDA GPU kernelsoffload to the GPU
12Inspect & debugsee inside
13Measure & cachebenchmark honestly
Speed recipea sensible default
!Gotchas & not supportedwhy it won't compile

How Numba behaves

Four ideas that explain the speedups — and the surprises — based on the Numba 5-minute guide and performance-tips docs.

the first call pays for compiling

Call 1 compiles and runs (slow); every later call with the same argument types reuses the cached machine code and flies.

compile run call 1 calls 2…n — cached, fast time

nopython vs object mode

In nopython mode the whole function becomes machine code. Object mode drops back to the interpreter for anything it can't type — losing most of the win.

your function @njit all → machine code fast ✓ object mode most → interpreter slow ✗

prange splits the loop

With parallel=True, prange hands slices of the iteration space to different threads; a final cross-thread step combines partial results.

prange(n) thread 0 thread 1 thread 2 thread 3 reduce → acc

the decorator family

One toolkit, several outputs: a plain compiled function, a NumPy ufunc, a neighborhood kernel, a compiled class, or a GPU kernel.

numba @ decorators @njit→ fast fn @vectorize→ ufunc @guvectorize→ gufunc @stencil→ kernel @cuda.jit→ GPU

Worth memorizing

@njit = @jit(nopython=True)the go-to; errors out if it can't fully compile
first call compileswarm up before benchmarking; cache=True persists it
Numba likes loopsplain loops over NumPy arrays are fast — unlike pure Python
no pandas / objectsNumPy arrays, scalars & math — not DataFrames or arbitrary dicts
parallel=True + prangeembarrassingly parallel loops across cores, no GIL
fastmath=Truerelax IEEE-754 so LLVM can vectorize (SIMD)
typed.List / typed.Dictplain Python lists/dicts don't cross into nopython cleanly
globals are frozencaptured as constants at compile — pass values as arguments
@vectorize → ufuncturn a scalar function into a broadcasting NumPy ufunc
inspect_types()see what Numba inferred when a compile goes wrong