Games need dice rolls, simulations require randomized inputs, and security systems demand unpredictable tokens. The random module provides pseudo-random number generation for games and simulations, while the secrets module offers cryptographically secure randomness for security-sensitive applications.

Statistical Distributions

Random numbers following specific distributions:

basic.py
# Basic random functions

import random
random.seed(42)

# Basic random
print("Basic random:")

# random() - [0.0, 1.0)
print("random():")
for _ in range(5):
    print(f"  {random.random():.6f}")

# randint(a, b) - [a, b] inclusive
print("\nrandint(1, 100):")
for _ in range(10):
    print(f"  {random.randint(1, 100)}", end=" ")
print()

# randrange(stop) - [0, stop)
print("\nrandrange(10):")
for _ in range(10):
    print(f"  {random.randrange(10)}", end=" ")
print()

# randrange(start, stop) - [start, stop)
print("\nrandrange(10, 20):")
for _ in range(10):
    print(f"  {random.randrange(10, 20)}", end=" ")
print()

# randrange(start, stop, step)
print("\nrandrange(0, 100, 10) - multiples of 10:")
for _ in range(10):
    print(f"  {random.randrange(0, 100, 10)}", end=" ")
print()

# uniform(a, b) - [a, b] or [a, b)
print("\nuniform(0.0, 10.0):")
for _ in range(5):
    print(f"  {random.uniform(0.0, 10.0):.2f}")

# triangular(low, high, mode)
print("\ntriangular(0, 100, 50):")
for _ in range(5):
    print(f"  {random.triangular(0, 100, 50):.2f}")

# choice(seq) - random element
print("\nchoice from list:")
colors = 
for _ in range(10):
    print(f"  {random.choice(colors)}", end=" ")
print()

# choices(seq, k=) - with replacement
print("\nchoices (with replacement, k=5):")
print(f"  {random.choices(colors, k=5)}")

# sample(seq, k) - without replacement
print("\nsample (without replacement, k=3):")
for _ in range(3):
    print(f"  {random.sample(colors, k=3)}")

# shuffle(list) - in-place shuffle
print("\nshuffle:")
numbers = list(range(1, 11))
print(f"Original: {numbers}")
random.shuffle(numbers)
print(f"Shuffled: {numbers}")

# gauss(mu, sigma) - Gaussian distribution
print("\ngauss(50, 10) - mean=50, stddev=10:")
for _ in range(10):
    print(f"  {random.gauss(50, 10):.2f}")

# seed() for reproducibility
print("\nSeeded random (seed=42):")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")  # Same sequence

# getstate() and setstate()
print("\nSave/restore state:")
state = random.getstate()
print(f"  {[random.randint(1, 10) for _ in range(3)]}")
random.setstate(state)
print(f"  {[random.randint(1, 10) for _ in range(3)]}")  # Same

# Random instance (separate state)
print("\nRandom instance:")
rng = random.Random(42)
print(f"  {[rng.randint(1, 100) for _ in range(5)]}")

# Basic random functions

import random
random.seed(42)

# Basic random
print("Basic random:")

# random() - [0.0, 1.0)
print("random():")
for _ in range(5):
    print(f"  {random.random():.6f}")

# randint(a, b) - [a, b] inclusive
print("\nrandint(1, 100):")
for _ in range(10):
    print(f"  {random.randint(1, 100)}", end=" ")
print()

# randrange(stop) - [0, stop)
print("\nrandrange(10):")
for _ in range(10):
    print(f"  {random.randrange(10)}", end=" ")
print()

# randrange(start, stop) - [start, stop)
print("\nrandrange(10, 20):")
for _ in range(10):
    print(f"  {random.randrange(10, 20)}", end=" ")
print()

# randrange(start, stop, step)
print("\nrandrange(0, 100, 10) - multiples of 10:")
for _ in range(10):
    print(f"  {random.randrange(0, 100, 10)}", end=" ")
print()

# uniform(a, b) - [a, b] or [a, b)
print("\nuniform(0.0, 10.0):")
for _ in range(5):
    print(f"  {random.uniform(0.0, 10.0):.2f}")

# triangular(low, high, mode)
print("\ntriangular(0, 100, 50):")
for _ in range(5):
    print(f"  {random.triangular(0, 100, 50):.2f}")

# choice(seq) - random element
print("\nchoice from list:")
colors = 
for _ in range(10):
    print(f"  {random.choice(colors)}", end=" ")
print()

# choices(seq, k=) - with replacement
print("\nchoices (with replacement, k=5):")
print(f"  {random.choices(colors, k=5)}")

# sample(seq, k) - without replacement
print("\nsample (without replacement, k=3):")
for _ in range(3):
    print(f"  {random.sample(colors, k=3)}")

# shuffle(list) - in-place shuffle
print("\nshuffle:")
numbers = list(range(1, 11))
print(f"Original: {numbers}")
random.shuffle(numbers)
print(f"Shuffled: {numbers}")

# gauss(mu, sigma) - Gaussian distribution
print("\ngauss(50, 10) - mean=50, stddev=10:")
for _ in range(10):
    print(f"  {random.gauss(50, 10):.2f}")

# seed() for reproducibility
print("\nSeeded random (seed=42):")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")  # Same sequence

# getstate() and setstate()
print("\nSave/restore state:")
state = random.getstate()
print(f"  {[random.randint(1, 10) for _ in range(3)]}")
random.setstate(state)
print(f"  {[random.randint(1, 10) for _ in range(3)]}")  # Same

# Random instance (separate state)
print("\nRandom instance:")
rng = random.Random(42)
print(f"  {[rng.randint(1, 100) for _ in range(5)]}")

# Basic random functions

import random
random.seed(42)

# Basic random
print("Basic random:")

# random() - [0.0, 1.0)
print("random():")
for _ in range(5):
    print(f"  {random.random():.6f}")

# randint(a, b) - [a, b] inclusive
print("\nrandint(1, 100):")
for _ in range(10):
    print(f"  {random.randint(1, 100)}", end=" ")
print()

# randrange(stop) - [0, stop)
print("\nrandrange(10):")
for _ in range(10):
    print(f"  {random.randrange(10)}", end=" ")
print()

# randrange(start, stop) - [start, stop)
print("\nrandrange(10, 20):")
for _ in range(10):
    print(f"  {random.randrange(10, 20)}", end=" ")
print()

# randrange(start, stop, step)
print("\nrandrange(0, 100, 10) - multiples of 10:")
for _ in range(10):
    print(f"  {random.randrange(0, 100, 10)}", end=" ")
print()

# uniform(a, b) - [a, b] or [a, b)
print("\nuniform(0.0, 10.0):")
for _ in range(5):
    print(f"  {random.uniform(0.0, 10.0):.2f}")

# triangular(low, high, mode)
print("\ntriangular(0, 100, 50):")
for _ in range(5):
    print(f"  {random.triangular(0, 100, 50):.2f}")

# choice(seq) - random element
print("\nchoice from list:")
colors = 
for _ in range(10):
    print(f"  {random.choice(colors)}", end=" ")
print()

# choices(seq, k=) - with replacement
print("\nchoices (with replacement, k=5):")
print(f"  {random.choices(colors, k=5)}")

# sample(seq, k) - without replacement
print("\nsample (without replacement, k=3):")
for _ in range(3):
    print(f"  {random.sample(colors, k=3)}")

# shuffle(list) - in-place shuffle
print("\nshuffle:")
numbers = list(range(1, 11))
print(f"Original: {numbers}")
random.shuffle(numbers)
print(f"Shuffled: {numbers}")

# gauss(mu, sigma) - Gaussian distribution
print("\ngauss(50, 10) - mean=50, stddev=10:")
for _ in range(10):
    print(f"  {random.gauss(50, 10):.2f}")

# seed() for reproducibility
print("\nSeeded random (seed=42):")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")
random.seed(42)
print(f"  {[random.randint(1, 100) for _ in range(5)]}")  # Same sequence

# getstate() and setstate()
print("\nSave/restore state:")
state = random.getstate()
print(f"  {[random.randint(1, 10) for _ in range(3)]}")
random.setstate(state)
print(f"  {[random.randint(1, 10) for _ in range(3)]}")  # Same

# Random instance (separate state)
print("\nRandom instance:")
rng = random.Random(42)
print(f"  {[rng.randint(1, 100) for _ in range(5)]}")

ranges.py
# Random ranges and distributions

import random
random.seed(42)

# Random ranges
print("Random ranges:")

# Range [0, n)
print("Range [0, 100):")
print(f"  {[random.randrange(100) for _ in range(10)]}")

# Range [a, b] inclusive
print("\nRange [10, 20] inclusive:")
print(f"  {[random.randint(10, 20) for _ in range(10)]}")

# Range [a, b) exclusive
print("\nRange [10, 20) exclusive:")
print(f"  {[random.randrange(10, 20) for _ in range(10)]}")

# Float range [a, b]
print("\nFloat range [0.0, 10.0]:")
print(f"  {[random.uniform(0.0, 10.0) for _ in range(5)]}")

# Negative range
print("\nNegative range [-10, 10]:")
print(f"  {[random.randint(-10, 10) for _ in range(10)]}")

# Dice roll (1-6)
print("\nDice rolls:")
rolls = [random.randint(1, 6) for _ in range(60)]
total_rolls = len(rolls)
for i in range(1, 7):
    count = rolls.count(i)
    percent = count / total_rolls * 100
    print(f"  {i}: {count} times ({percent:.1f}%)")

# Coin flip
print("\nCoin flips:")
flips = [random.choice(['H', 'T']) for _ in range(40)]
heads = flips.count('H')
tails = flips.count('T')
total_flips = len(flips)
print(f"  Heads: {heads} ({heads / total_flips * 100:.1f}%)")
print(f"  Tails: {tails} ({tails / total_flips * 100:.1f}%)")

# Weighted random
print("\nWeighted random:")
outcomes = ['common', 'uncommon', 'rare', 'epic']
weights = [50, 30, 15, 5]
results = random.choices(outcomes, weights=weights, k=40)
total_results = len(results)
for outcome in outcomes:
    count = results.count(outcome)
    percent = count / total_results * 100
    print(f"  {outcome}: {count} ({percent:.1f}%)")

# Probability check
print("\n20% probability:")
probability_trials = 40
successes = sum(1 for _ in range(probability_trials) if random.random() < 0.20)
print(f"  Successes: {successes} ({successes / probability_trials * 100:.1f}%)")

# Random steps
print("\nRandom steps (2, 5, 10):")
steps = [random.choice([2, 5, 10]) for _ in range(10)]
print(f"  {steps}")

# Multiples of 5
print("\nRandom multiples of 5 [0, 100):")
print(f"  {[random.randrange(0, 100, 5) for _ in range(10)]}")

# Random percentage
print("\nRandom percentages:")
percentages = [random.uniform(0, 100) for _ in range(5)]
for p in percentages:
    print(f"  {p:.2f}%")

# Helper functions
def rand_range(a, b):
    """Random int in [a, b] inclusive."""
    return random.randint(a, b)

def rand_float(a, b):
    """Random float in [a, b]."""
    return random.uniform(a, b)

def probability(p):
    """Return True with probability p."""
    return random.random() < p

print("\nHelper functions:")
print(f"rand_range(10, 20): {[rand_range(10, 20) for _ in range(5)]}")
print(f"rand_float(0, 1): {[rand_float(0, 1) for _ in range(5)]}")
print(f"probability(0.3): {[probability(0.3) for _ in range(10)]}")

shuffle.py
# Shuffling and sampling

import random
random.seed(42)

# Shuffling
print("Shuffling:")

# Shuffle list (in-place)
names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
print(f"Original: {names}")
random.shuffle(names)
print(f"Shuffled: {names}")

# Shuffle with seed
print("\nShuffle with seed:")
nums1 = list(range(1, 11))
nums2 = list(range(1, 11))

random.seed(42)
random.shuffle(nums1)
random.seed(42)
random.shuffle(nums2)

print(f"First:  {nums1}")
print(f"Second: {nums2}")
print(f"Same: {nums1 == nums2}")

# Sample (without replacement)
print("\nSample (without replacement):")
population = list(range(1, 11))
for _ in range(5):
    sample = random.sample(population, k=3)
    print(f"  {sample}")

# Choices (with replacement)
print("\nChoices (with replacement):")
for _ in range(5):
    choices = random.choices(population, k=3)
    print(f"  {choices}")

# Sample entire population (shuffle alternative)
print("\nSample entire population:")
shuffled = random.sample(population, k=len(population))
print(f"  {shuffled}")

# Pick random element
print("\nPick random element:")
colors = ['red', 'green', 'blue', 'yellow', 'purple']
for _ in range(10):
    color = random.choice(colors)
    print(f"  {color}", end=" ")
print()

# Weighted sampling
print("\nWeighted sampling:")
items = ['common', 'uncommon', 'rare', 'legendary']
weights = [50, 30, 15, 5]

print("Weighted choices (k=10):")
for _ in range(5):
    result = random.choices(items, weights=weights, k=10)
    print(f"  {result}")

# Random permutation
print("\nRandom permutations of 'ABCD':")
chars = ['A', 'B', 'C', 'D']
for _ in range(5):
    perm = random.sample(chars, k=len(chars))
    print(f"  {''.join(perm)}")

# Deal cards
print("\nDeal cards:")
suits = ['♠', '♥', '♦', '♣']
ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
deck = [f"{rank}{suit}" for suit in suits for rank in ranks]

random.shuffle(deck)
print(f"Original (first 13): {deck[:13]}")

# Deal hands
print("\nDeal 4 hands of 5 cards:")
for player in range(4):
    hand = deck[player*5:(player+1)*5]
    print(f"  Player {player+1}: {hand}")

# Random subset
print("\nRandom subsets:")
data = list(range(1, 21))
for size in [3, 5, 10]:
    subset = random.sample(data, k=size)
    print(f"  Size {size}: {subset}")

# Random pairs
print("\nRandom pairs:")
people = ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank']
shuffled = random.sample(people, k=len(people))
pairs = [(shuffled[i], shuffled[i+1]) for i in range(0, len(shuffled)-1, 2)]
for pair in pairs:
    print(f"  {pair[0]} <-> {pair[1]}")

strings.py
# Random strings and data

import random
import string
random.seed(42)

# Random strings
print("Random strings:")

# Random letters
print("Random letters:")
letters = [random.choice(string.ascii_lowercase) for _ in range(10)]
print(f"  {''.join(letters)}")

# Random uppercase
print("\nRandom uppercase:")
uppercase = [random.choice(string.ascii_uppercase) for _ in range(10)]
print(f"  {''.join(uppercase)}")

# Random digits
print("\nRandom digits:")
digits = [random.choice(string.digits) for _ in range(10)]
print(f"  {''.join(digits)}")

# Random alphanumeric
print("\nRandom alphanumeric:")
def random_alphanumeric(length):
    """Generate random alphanumeric string."""
    return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

for _ in range(5):
    print(f"  {random_alphanumeric(12)}")

# Random password
print("\nRandom passwords:")
def random_password(length=12):
    """Generate random password with all character types."""
    chars = string.ascii_letters + string.digits + string.punctuation
    while True:
        password = ''.join(random.choices(chars, k=length))
        # Ensure at least one of each type
        if (any(c.islower() for c in password) and
            any(c.isupper() for c in password) and
            any(c.isdigit() for c in password) and
            any(c in string.punctuation for c in password)):
            return password

for _ in range(5):
    print(f"  {random_password(16)}")

# Random hex
print("\nRandom hex strings:")
def random_hex(length):
    """Generate random hex string."""
    return ''.join(random.choices('0123456789abcdef', k=length))

for _ in range(5):
    print(f"  {random_hex(16)}")

# Random UUID-like
print("\nRandom UUID-like:")
def random_uuid():
    """Generate random UUID-like string."""
    return f"{random_hex(8)}-{random_hex(4)}-{random_hex(4)}-{random_hex(4)}-{random_hex(12)}"

for _ in range(3):
    print(f"  {random_uuid()}")

# Random email
print("\nRandom emails:")
def random_email():
    """Generate random email address."""
    username = ''.join(random.choices(string.ascii_lowercase, k=8))
    domain = random.choice(['gmail.com', 'yahoo.com', 'hotmail.com', 'example.com'])
    return f"{username}@{domain}"

for _ in range(5):
    print(f"  {random_email()}")

# Random phone
print("\nRandom phone numbers:")
def random_phone():
    """Generate random phone number."""
    area = random.randint(200, 999)
    exchange = random.randint(200, 999)
    number = random.randint(0, 9999)
    return f"({area:03d}) {exchange:03d}-{number:04d}"

for _ in range(5):
    print(f"  {random_phone()}")

# Random name
print("\nRandom names:")
first_names = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank']
last_names = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Miller']

for _ in range(5):
    name = f"{random.choice(first_names)} {random.choice(last_names)}"
    print(f"  {name}")

# Random date
print("\nRandom dates:")
import datetime

def random_date(start_year=2020, end_year=2024):
    """Generate random date."""
    year = random.randint(start_year, end_year)
    month = random.randint(1, 12)
    day = random.randint(1, 28)  # Simplified
    return datetime.date(year, month, day)

for _ in range(5):
    print(f"  {random_date()}")

# Random color
print("\nRandom RGB colors:")
def random_color():
    """Generate random RGB color."""
    r = random.randint(0, 255)
    g = random.randint(0, 255)
    b = random.randint(0, 255)
    return f"#{r:02x}{g:02x}{b:02x}"

for _ in range(5):
    print(f"  {random_color()}")

distributions.py
# Distributions

import random
import math
random.seed(42)

# Distributions
print("Distributions:")
trials = 50

# Uniform distribution [0, 100)
print("Uniform distribution [0, 100):")
uniform = [0] * 10
for _ in range(trials):
    value = random.randint(0, 99)
    bin_idx = value // 10
    uniform[bin_idx] += 1

for i, count in enumerate(uniform):
    bar = 'â–ˆ' * max(1, count // 2)
    print(f"[{i*10}-{(i+1)*10}): {count:4d} ({count/trials*100:.1f}%) {bar}")

# Gaussian (normal) distribution
print("\nGaussian distribution (mean=50, stddev=10):")
gaussian = [0] * 10
for _ in range(trials):
    value = random.gauss(50, 10)
    bin_idx = max(0, min(9, int(value // 10)))
    gaussian[bin_idx] += 1

for i, count in enumerate(gaussian):
    bar = 'â–ˆ' * max(1, count // 2)
    print(f"[{i*10}-{(i+1)*10}): {count:4d} ({count/trials*100:.1f}%) {bar}")

# Exponential distribution
print("\nExponential distribution (lambda=0.1):")
def exponential_random(lambda_param):
    """Generate exponential random variable."""
    return -math.log(1 - random.random()) / lambda_param

exponential = [0] * 10
for _ in range(trials):
    value = exponential_random(0.1)
    bin_idx = min(9, int(value // 10))
    exponential[bin_idx] += 1

for i, count in enumerate(exponential):
    bar = 'â–ˆ' * max(1, count // 2)
    print(f"[{i*10}-{(i+1)*10}): {count:4d} ({count/trials*100:.1f}%) {bar}")

# Binomial distribution (coin flips)
print("\nBinomial distribution (10 flips, p=0.5):")
binomial = [0] * 11
for _ in range(trials):
    heads = sum(random.random() < 0.5 for _ in range(10))
    binomial[heads] += 1

print("Number of heads:")
for i, count in enumerate(binomial):
    print(f"{i:2d}: {count:4d} ({count/trials*100:.1f}%)")

# Triangle distribution
print("\nTriangle distribution [0, 100, mode=50]:")
triangle = [0] * 10
for _ in range(trials):
    value = random.triangular(0, 100, 50)
    bin_idx = min(9, int(value // 10))
    triangle[bin_idx] += 1

for i, count in enumerate(triangle):
    bar = 'â–ˆ' * max(1, count // 2)
    print(f"[{i*10}-{(i+1)*10}): {count:4d} ({count/trials*100:.1f}%) {bar}")

# Beta distribution (using acceptance-rejection)
print("\nBeta-like distribution:")
def beta_random(alpha, beta):
    """Simple beta random using acceptance-rejection."""
    while True:
        u = random.random()
        v = random.random()
        if v <= u**(alpha-1) * (1-u)**(beta-1):
            return u

beta_dist = [0] * 10
for _ in range(trials):
    value = beta_random(2, 5) * 100
    bin_idx = min(9, int(value // 10))
    beta_dist[bin_idx] += 1

for i, count in enumerate(beta_dist):
    bar = 'â–ˆ' * max(1, count // 2)
    print(f"[{i*10}-{(i+1)*10}): {count:4d} ({count/trials*100:.1f}%) {bar}")

# Poisson distribution
print("\nPoisson distribution (lambda=5):")
def poisson_random(lambda_param):
    """Generate Poisson random variable."""
    L = math.exp(-lambda_param)
    k = 0
    p = 1.0
    while p > L:
        k += 1
        p *= random.random()
    return k - 1

poisson = [0] * 15
for _ in range(trials):
    events = poisson_random(5.0)
    if events < len(poisson):
        poisson[events] += 1

print("Number of events:")
for i, count in enumerate(poisson[:12]):
    print(f"{i:2d}: {count:4d} ({count/trials*100:.1f}%)")

pseudo-random Numbers generated by a deterministic algorithm that appear random but are reproducible given the same seed - suitable for games and simulations but not security.
seed() Initializes the random number generator to produce reproducible sequences - essential for testing and debugging randomized code.
choice vs sample choice() picks one item with replacement, sample() picks multiple unique items without replacement, choices() picks multiple with replacement.

Exercise: practical.py

Create a dice game that rolls multiple dice and determines the winner