Python's random module generates pseudo-random numbers and provides utilities for sampling, shuffling, and simple probability simulations.

Two key ideas:

  • It's pseudo-random (deterministic given a seed).
  • It's not cryptographically secure (use secrets for security).

Basic Random Numbers

import random
 
print(random.random())        # float in [0.0, 1.0)
print(random.uniform(10, 20)) # float in [10.0, 20.0]
print(random.randint(1, 6))   # int in [1, 6]
print(random.randrange(0, 10, 2))  # 0,2,4,6,8

Common gotcha: randint vs randrange

  • randint(a, b) includes both endpoints.
  • randrange(a, b) is like range(a, b) (excludes b).

Choosing Random Elements

import random
 
items = ["red", "green", "blue"]
print(random.choice(items))
 
# Multiple choices (with replacement)
print(random.choices(items, k=5))
 
# Weighted choices
weights = [0.1, 0.2, 0.7]
print(random.choices(items, weights=weights, k=10))
 
# Sample without replacement
print(random.sample(items, k=2))

Shuffling

import random
 
deck = list(range(1, 53))
random.shuffle(deck)
print(deck[:5])

shuffle() mutates in place.

Reproducibility with Seeds

If you want repeatable results (tests, simulations), set a seed.

import random
 
random.seed(42)
print([random.randint(1, 10) for _ in range(5)])
 
random.seed(42)
print([random.randint(1, 10) for _ in range(5)])  # same output

You can seed with an int, float, str, bytes, or None.

Rather than using the global RNG, create a dedicated one:

import random
 
rng = random.Random(123)
print(rng.random())
print(rng.randint(1, 6))

This is cleaner for libraries and tests.

Distributions

The module includes helpers for common distributions:

import random
 
# Normal distribution
print(random.gauss(mu=0, sigma=1))
 
# Log-normal
print(random.lognormvariate(mu=0, sigma=1))
 
# Exponential (lambda)
print(random.expovariate(lambd=1.5))
 
# Triangular
print(random.triangular(low=0, high=10, mode=3))
 
# Beta
print(random.betavariate(alpha=2, beta=5))

Simple Simulation: Dice Rolls

import random
from collections import Counter
 
N = 100_000
rolls = [random.randint(1, 6) for _ in range(N)]
counts = Counter(rolls)
 
for face in range(1, 7):
    print(face, counts[face] / N)

Random Strings / IDs (Non-Security)

import random
import string
 
alphabet = string.ascii_letters + string.digits
 
def random_id(n=12):
    return ''.join(random.choice(alphabet) for _ in range(n))
 
print(random_id())

If this is for auth tokens, password resets, etc. use secrets.

random vs secrets

  • Use random for games, sampling, simulations, quick tests.
  • Use secrets for anything security-related.
import secrets
 
print(secrets.token_hex(16))
print(secrets.choice(["a", "b", "c"]))

Practical Testing Pattern

import random
 
def test_my_algorithm_is_stable():
    rng = random.Random(0)
    data = [rng.randint(0, 1000) for _ in range(1000)]
 
    # Run algorithm and assert deterministic outcome
    result = sorted(data)[:10]
    assert result == [0, 0, 2, 2, 3, 3, 4, 4, 6, 6]

Summary

The random module is great for non-security randomness:

  • random(), randint(), randrange() for numbers
  • choice(), sample(), choices() for selection
  • shuffle() for in-place shuffling
  • seed() and Random() for reproducibility

For security-sensitive randomness, use secrets.

React to this post: