math & random Modules
Python's numeric type system covers the basic arithmetic operators, but anything beyond +, -, *, / usually means reaching for the math module — square roots, rounding, trigonometry, logarithms, and mathematical constants. Alongside it, the random module provides tools for generating pseudo-random numbers, which are essential for simulations, games, sampling, and shuffling data. Both are part of the standard library, so no installation is required.
The `math` Module
math works exclusively with int/float numbers (not complex numbers — that's what the separate cmath module is for) and exposes both functions and constants.
import math print(math.sqrt(64)) print(math.floor(4.7)) print(math.ceil(4.2)) print(math.pi) print(math.pow(2, 10)) print(2 ** 10)
8.0 4 5 3.141592653589793 1024.0 1024
Notice that math.pow() always returns a float, even for whole-number results, while the built-in ** operator returns an int when given two integers. For everyday exponentiation, ** is usually simpler and preferred; math.pow() exists mainly for consistency with other math functions and for cases where you specifically want a float back.
Trigonometry and Logarithms
math also includes the standard trigonometric functions, which work in radians, not degrees — use math.radians() to convert a degree value first.
import math angle_degrees = 90 angle_radians = math.radians(angle_degrees) print(angle_radians) print(math.sin(angle_radians)) print(math.cos(math.radians(0))) print(math.log(math.e)) print(math.log(100, 10))
1.5707963267948966 1.0 1.0 1.0 2.0
math.log(x) computes the natural logarithm (base e) by default; passing a second argument computes the logarithm in that base instead.
Common `math` Functions at a Glance
Function / constant | Purpose |
|---|---|
| Square root |
| Round down / up to nearest integer |
| x raised to the power y, always returns a float |
| The constants π and e |
| Trigonometric functions (radians) |
| Convert degrees to radians |
| Logarithm, natural by default |
The `random` Module
random generates pseudo-random values — numbers that look statistically random but are actually produced by a deterministic algorithm seeded from some starting state (by default, something like the system clock).
import random print(random.random()) # float in [0.0, 1.0) print(random.randint(1, 6)) # int in [1, 6], both ends inclusive print(random.choice(["rock", "paper", "scissors"])) deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] random.shuffle(deck) # shuffles in place, returns None print(deck) hand = random.sample(deck, 3) # pick 3 unique items without replacement print(hand)
0.7304598921453987 4 paper [7, 2, 9, 4, 1, 10, 6, 3, 8, 5] [9, 6, 1]
A few distinctions worth remembering: random.shuffle() mutates the list in place and returns None (a common source of bugs when someone writes deck = random.shuffle(deck)), while random.sample() returns a new list and leaves the original untouched. random.choice() picks one element and can pick the same element again on a later call; random.sample() never repeats an element within a single call.
Common `random` Functions at a Glance
Function | Returns |
|---|---|
| Float between 0.0 (inclusive) and 1.0 (exclusive) |
| Integer between a and b, both inclusive |
| One random element from a sequence |
| Shuffles the list in place; returns |
| A new list of k unique elements, no repeats |
import secrets token = secrets.token_hex(16) print(token)
e4f3a1c9b02d7e6f1a4c8b3d5f0a9e7c
Seeding for Reproducible Randomness
By default, each run of a program produces a different sequence of "random" values. Calling random.seed(value) resets the internal state to a known point, so the exact same sequence of calls will always produce the exact same results. This is extremely useful for writing reproducible tests, debugging simulations, or sharing an exact scenario with someone else.
import random random.seed(42) print([random.randint(1, 100) for _ in range(5)]) random.seed(42) print([random.randint(1, 100) for _ in range(5)]) random.seed(7) print([random.randint(1, 100) for _ in range(5)])
[82, 15, 4, 95, 36] [82, 15, 4, 95, 36] [51, 80, 27, 44, 69]
The first two calls use the same seed (42) and produce identical sequences, while the third call with seed 7 produces a completely different — but equally reproducible — sequence.
Quick Reference
mathworks with real numbers only; angles for trig functions are in radians.**is generally preferred overmath.pow()for simple exponentiation.random.random(),randint(),choice(),shuffle(), andsample()cover most everyday randomness needs.Use
secrets, notrandom, for anything security-sensitive.random.seed()makes a sequence of random calls reproducible — useful for tests and simulations.