The random module is one of Python's most versatile standard libraries. Whether you need to generate random numbers, pick items from a list, shuffle data, or create simulations, random has you covered. This complete guide takes you from the basics to advanced techniques with practical examples.

Generating random data is essential across many fields: game development, software testing, scientific simulations, statistical sampling, machine learning, and beyond. Python makes this work simple and intuitive with its built-in random module.

If you are just getting started, check out our beginner's guide to Python before diving into this article.

Why Use the Random Module?

The random module implements pseudo-random number generators for various distributions. Although the numbers appear random, they are produced by a deterministic algorithm. For applications that require cryptographic randomness, Python offers the secrets module.

Key use cases include:

  • Games: generating positions, attributes, loot boxes, and unpredictable behaviors
  • Testing: creating varied and representative test data
  • Simulations: modeling random phenomena like queues, traffic, and finance
  • Sampling: selecting representative subsets from populations
  • Machine Learning: shuffling data, initializing weights, and creating train/test splits

Another useful function is random.getrandbits(k), which returns an integer with k random bits. This function is efficient for generating large numbers without manually specifying ranges.

import random

8-bit number (0 to 255)

print(random.getrandbits(8)) # Example: 187

16-bit number (0 to 65535)

print(random.getrandbits(16)) # Example: 42351

With random, you can simulate complex scenarios in just a few lines of code. Let's explore the main features in practice.

Core Functions of the Random Module

The module offers dozens of functions. The official Python documentation is the complete reference, but we will focus on the most commonly used ones. All functions share the same underlying generator, so you can freely mix calls to different functions without any issues.

random.random() — Random Float Number

The most basic function: returns a random float in the range [0.0, 1.0).

import random

print(random.random()) # Example: 0.3746325874916233 print(random.random()) # Example: 0.8921567432810459

Useful for generating probabilities, percentages, or normalizing data.

random.randint() — Random Integer

Returns a random integer between A and B (inclusive):

import random

dice = random.randint(1, 6) print(f'You rolled a {dice}')

lottery = random.randint(1, 60) print(f'Lottery number: {lottery}')

This is probably the most popular function in the module. Use randint whenever you need an integer within a range.

random.randrange() — Integer with Step

Similar to randint, but accepts an optional step parameter, just like the range() function:

import random

Random even number between 0 and 20

even = random.randrange(0, 21, 2) print(f'Even number: {even}')

Multiple of 5 between 0 and 50

mult5 = random.randrange(0, 51, 5) print(f'Multiple of 5: {mult5}')

This function is useful when you need numbers that follow a specific pattern, such as generating even indices or arithmetic progression values.

random.uniform() — Float in a Custom Range

Similar to random(), but lets you set your own bounds:

import random

temperature = random.uniform(36.0, 40.0) print(f'Simulated temperature: {temperature:.1f}°C')

price = random.uniform(10.50, 99.90) print(f'Random price: ${price:.2f}')

random.choice() — Pick a Random Item

Selects one random element from a sequence (list, tuple, string):

import random

fruits = ['apple', 'banana', 'orange', 'grape', 'strawberry'] print(random.choice(fruits)) # Example: 'orange'

With strings

letter = random.choice('ABCDEFGH') print(letter) # Example: 'C'

random.choice() is widely used in raffles, games, and A/B testing.

To better understand how lists work in Python, check out our complete guide to list manipulation.

random.choices() — Multiple Items with Replacement

Selects K items from a population, allowing repeats. Supports weights to define probabilities:

import random

colors = ['red', 'blue', 'green'] weights = [0.5, 0.3, 0.2] # 50% red, 30% blue, 20% green

result = random.choices(colors, weights=weights, k=10) print(result)

Example: ['red', 'blue', 'red', 'green', 'blue', ...]

This function is fantastic for simulating custom probability distributions.

random.sample() — Sample Without Replacement

Selects K unique items from a population, no repeats:

import random

students = ['Alice', 'Bob', 'Carol', 'Daniel', 'Emma', 'Frank'] selected = random.sample(students, 3) print(f'Selected: {selected}')

Lottery numbers

lottery = random.sample(range(1, 61), 6) print(f'Lottery: {sorted(lottery)}')

Use sample when each item can be chosen only once, such as raffles, data splits for machine learning, and cross-validation.

random.shuffle() — Shuffle a List

Shuffles the elements of a list in-place (modifies the original list):

import random

cards = ['A♠', 'K♠', 'Q♠', 'J♠', '10♠', '9♠', '8♠'] random.shuffle(cards) print(cards) # Example: ['Q♠', 'A♠', '10♠', 'K♠', '9♠', 'J♠', '8♠']

For training data

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] random.shuffle(data) train, test = data[:7], data[7:] print(f'Train: {train}') print(f'Test: {test}')

Shuffling data is a critical preprocessing step in machine learning to avoid order bias.

Working with Seeds

Pseudo-random numbers are generated from a seed value. If you set the same seed, you get the exact same sequence. This is essential for reproducibility in scientific experiments and machine learning.

import random

random.seed(42) print(random.randint(1, 100)) # Always 82 print(random.random()) # Always 0.639426798...

random.seed(42) # Resetting the seed print(random.randint(1, 100)) # 82 again

According to Real Python, using seeds is one of the best practices in data science, as it guarantees your experiments can be reproduced by other researchers.

Pro Tip: Capturing Generator State

By default, Python seeds the generator from os.urandom(), which draws from truly random OS sources. You can capture the current state with random.getstate() and restore it later. This is especially useful for debugging — you can save the state before a sequence of operations, test repeatedly, and always return to the same starting point.

import random

state = random.getstate()

Generate as many numbers as needed...

random.setstate(state) # Back to the previous state

Statistical Distributions

The random module provides functions for various statistical distributions, which are fundamental for scientific simulations:

Uniform Distribution

import random

Uniformly distributed values between 0 and 10

for _ in range(5): print(random.uniform(0, 10))

Normal (Gaussian) Distribution

import random

Mean 0, standard deviation 1

for _ in range(5): print(random.gauss(0, 1))

Simulated population height

height = random.gauss(170, 10) # Mean 170cm, SD 10cm print(f'Simulated height: {height:.1f} cm')

Triangular Distribution

The triangular distribution is useful when you know the minimum, maximum, and most likely (mode) value of a phenomenon:

import random

Simulate task completion time (optimistic: 2h, likely: 4h, pessimistic: 8h)

estimated_time = random.triangular(2, 8, 4) print(f'Estimated time: {estimated_time:.1f} hours')

Popular in project management simulations (PERT)

duration = random.triangular(10, 30, 15) print(f'Simulated duration: {duration:.1f} days')

This distribution is widely used in engineering simulations and project management when historical data is limited.

Exponential Distribution

import random

Simulate inter-arrival times in a queue

lambda_param = 2.0 # 2 arrivals per minute time = random.expovariate(lambda_param) print(f'Time until next arrival: {time:.2f} minutes')

For more robust distribution handling, NumPy offers optimized functions. Check out the numpy.random module for high-performance scientific applications. If you want to dive deeper into NumPy, see our complete NumPy guide.

Real-World Use Cases

1. Dice Roll Simulator

import random

def roll_dice(sides=6): return random.randint(1, sides)

Simulate 1000 rolls

results = [rolldice() for in range(1000)] frequencies = {i: results.count(i) for i in range(1, 7)} print(frequencies)

2. Random Password Generator

import random
import string

def generate_password(length=12): chars = string.asciiletters + string.digits + '!@#$%&*' return ''.join(random.choice(chars) for in range(length))

print(generate_password()) # Example: 'aK7$mP9@xL2#'

For secure passwords, prefer the secrets module, which uses cryptographically secure sources.

3. Monte Carlo Simulation

One of the most powerful applications: estimating Pi using the Monte Carlo method:

import random

def estimatepi(points=100000): inside = 0 for in range(points): x, y = random.random(), random.random() if xx + yy <= 1: inside += 1 return 4 * inside / points

print(f'Estimated Pi: {estimate_pi()}') # ~3.1415

4. Train-Test Split for Machine Learning

import random

data = list(range(100)) random.shuffle(data)

split = int(0.8 * len(data)) train = data[:split] test = data[split:]

print(f'Train: {len(train)} samples') print(f'Test: {len(test)} samples')

Random vs NumPy Random vs Secrets

Python offers three main approaches to randomness:

Module When to Use Performance
random General purpose, games, simple scripts Good
numpy.random Large data volumes, multidimensional arrays Excellent (vectorized)
secrets Passwords, tokens, cryptography Moderate

The NumPy random is significantly faster for large datasets because it generates entire arrays at once using optimized C code. The secrets module is mandatory when security is critical.

Best Practices

  1. Always use a seed for reproducibility in experiments and scientific tests.
  2. Do not use random for cryptography — use the secrets module instead.
  3. Document your seeds so other researchers can replicate your results.
  4. Prefer numpy.random for large data volumes.
  5. Be careful with shuffle on large lists — it modifies the list in-place. If you need to preserve the original, make a copy with copy = original.copy() before shuffling.
  6. Test your generators: always verify that generated values fall within expected ranges, especially in critical applications like financial or medical simulations.

Performance and Limitations

The random module uses the Mersenne Twister algorithm (MT19937), which is fast and passes most statistical randomness tests. However, it is not suitable for:

  • Cryptography (use secrets)
  • Simulations requiring enormous quantities of random numbers (prefer NumPy)
  • Applications sensitive to long-period patterns

The Mersenne Twister period is 2^19937 − 1, which is more than enough for virtually any non-cryptographic application. In practical terms, this means you can generate trillions of numbers before the cycle repeats. For applications that demand even more performance, NumPy implements the same algorithm in C with vectorization, achieving up to 50x faster throughput for large volumes. To learn more about the algorithm, the GeeksforGeeks article has an excellent technical deep dive.

Conclusion

Python's random module is a powerful and versatile tool every developer should master. From simple dice rolls to complex Monte Carlo simulations, it provides the essential functionality to work with randomness productively and reliably.

Quick reference of the most important functions:

  • random() — float in [0, 1)
  • randint(a, b) — integer between a and b
  • choice(seq) — one random item
  • sample(pop, k) — sample without replacement
  • shuffle(list) — shuffle in-place
  • seed(n) — set seed for reproducibility

Be sure to consult the official documentation to explore all available functions. Practice with the examples in this article and soon you will use the random module confidently in your projects.

To continue learning, also check out the interactive tutorial on PYnative and the W3Schools random examples.