Random Numbers with Random
Learn to generate random numbers in Python using the random module. Covers randint, uniform, random, choice, and sample with practical examples, troubleshooting, and what to study next.
Focus: generate random numbers with the random module
Randomness is a fundamental need in programming, from seeding test data to powering game mechanics. The Python random module supplies a suite of functions to generate deterministic pseudorandom numbers, enabling you to simulate chance, shuffle collections, and create realistic data. Without these tools, you'd be forced to rely on external APIs or hard-coded sequences, both of which are slow and inflexible for everyday coding.
The problem this lesson solves
When you need non-deterministic behavior in a Python program—rolling dice, picking a random user, or generating a unique ID—Python's random module provides the answer. Without it, you're stuck writing brittle code that always produces the same output. The module gives you a single, standard library to produce reproducible random numbers, which is essential for testing, gaming, and data science.
Core concept / mental model
Think of the random module as a digital dice factory. Each call to a function like randint() or uniform() rolls an invisible pair of dice that produce a number within a range you define. The module uses a pseudorandom number generator called the Mersenne Twister, which means the sequence of numbers is deterministic given a starting seed. This is crucial because for debugging and testing, you can set the seed to get the same "random" sequence every time.
Key functions at a glance
| Function | Purpose | Example |
|---|---|---|
random() |
Float in [0.0, 1.0) | random.random() → 0.374... |
randint(a,b) |
Random integer between a and b (inclusive both ends) | random.randint(1,6) → 4 |
uniform(a,b) |
Random float between a and b | random.uniform(0.0, 1.0) → 0.765... |
choice(seq) |
Pick a random element from a sequence | random.choice(['a','b','c']) → 'b' |
sample(seq,k) |
Pick k unique elements from a population | random.sample(range(10),3) → [2,7,4] |
Pro Tip: The
random()function is the foundation for all others.randint(a,b)is implemented asa + int(random() * (b - a + 1)). Understanding this helps you debug edge cases.
How it works step by step
Let's build random numbers piece by piece.
Step 1: Import the module
import random
This loads all the functions you'll need.
Step 2: Generate a simple random float
default_random = random.random()
print(default_random) # 0.748237... (changes each run)
Step 3: Set the seed for reproducibility
random.seed(42) # Set once at the top of your script
print(random.random()) # 0.640... (always the same)
The seed initializes the internal state. Use the same seed for testing and a different one for production.
Step 4: Generate integers in a range
dice = random.randint(1, 6) # Inclusive both ends: 1,2,3,4,5,6
lottery = random.randrange(1, 50, 5) # 1,6,11,16,21,26,31,36,41,46
randrange is like range() but returns a random number from that sequence.
Step 5: Work with sequences
fruits = ['apple', 'banana', 'cherry', 'date']
pick = random.choice(fruits)
print(pick) # 'banana'
# Pick 2 unique fruits
subset = random.sample(fruits, 2)
print(subset) # ['date', 'apple']
Multiple Calls: Each call to
random()advances the internal state. If you need multiple related numbers, call the function multiple times—not once and reuse the same value.
Hands-on walkthrough
Now you'll build a simulated dice game for two players.
Basic dice sim
import random
def roll_dice():
return random.randint(1, 6)
player1 = roll_dice()
player2 = roll_dice()
print(f"Player 1: {player1}, Player 2: {player2}")
if player1 > player2:
print("Player 1 wins!")
elif player2 > player1:
print("Player 2 wins!")
else:
print("It's a tie!")
Expected output (varies):
Player 1: 4, Player 2: 6
Player 2 wins!
Adding randomness to sequences
students = ["Alice", "Bob", "Charlie", "Diana"]
random.shuffle(students) # Modifies the list in place!
print("After shuffle:", students)
# Randomly select a subset of winners
winners = random.sample(students, 2)
print("Winners:", winners)
Expected output (example):
After shuffle: ['Diana', 'Charlie', 'Alice', 'Bob']
Winners: ['Alice', 'Charlie']
Generating a random password
import random
import string
def random_password(length=12):
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(length))
print(random_password())
print(random_password(8))
Expected output (varies):
aB3kLx9QmN5r
TsPj1Fc7
Reproducible random data for testing
random.seed(99)
print("Seed 99:", [random.randint(1, 100) for _ in range(3)])
random.seed(99)
print("Seed 99 again:", [random.randint(1, 100) for _ in range(3)])
Expected output (always the same):
Seed 99: [39, 84, 22]
Seed 99 again: [39, 84, 22]
Remember: After calling
random.seed(), all subsequentrandomfunction calls use that seeded state until you callseed()again.
Compare options / when to choose what
| Function | Return type | Range | Use case |
|---|---|---|---|
random() |
Float | [0.0, 1.0) | Base for all others; rarely used directly |
randint(a,b) |
Integer | a ≤ x ≤ b | Dice, lottery numbers, indices for lists |
uniform(a,b) |
Float | a ≤ x ≤ b | Continuous values like percentages, coordinates |
choice(seq) |
Element | Any sequence | Single random pick from list/tuple |
sample(seq,k) |
List | Without replacement | Subset selection, random survey |
shuffle(seq) |
Mutates list | In-place reorder | Card shuffling, random ordering |
When to use each:
- randint(): When you need a whole number in a specific interval. Most common for games.
- uniform(): For continuous random values (e.g., random delays, dimensions).
- sample(): When you need distinct elements without repetition (e.g., picking winners).
- shuffle(): When you want to randomly reorder a list (note: it modifies the original).
- choice(): For a single random pick, especially from a large population.
Troubleshooting & edge cases
1. Empty sequence with choice() or sample()
random.choice([]) # IndexError: Cannot choose from an empty sequence
random.sample([], 2) # ValueError: Sample larger than population or is negative
Fix: Always check the sequence is non-empty before calling.
2. Sample larger than population
random.sample([1,2,3], 5) # ValueError: Sample larger than population
Fix: Use random.choices() (with replacement) instead, or reduce k.
3. Forgetting that shuffle() modifies the list
numbers = [1,2,3]
saved = numbers
random.shuffle(numbers)
print(saved) # [3,1,2] — both variables point to the same list!
Fix: Make a copy first: copy_list = numbers[:]
4. Inconsistent seeds across calls
random.seed(5)
a = random.random()
b = random.random() # This is the second number from seed 5, not the same as a
Fix: If you need the same sequence, call seed() once before both calls.
5. Using random() for security-sensitive operations
random is not cryptographically secure. For passwords, tokens, or anything security-related, use secrets module instead.
What you learned & what's next
You now know how to generate random numbers with the random module:
- Understanding the Mersenne Twister pseudorandom generator
- Using random(), randint(), uniform(), choice(), sample(), and shuffle()
- Setting seeds for reproducibility in testing
- Handling common edge cases like empty sequences and population size
- Choosing the right function for your specific scenario
This randomness engine is foundational for simulations, games, and data sampling. Your next lesson explores the datetime module to handle dates and times in Python, another core building block for real-world applications. Head there to learn how to work with timestamps, timedeltas, and date arithmetic.
Practice recap
Great work mastering random number generation! To cement your skills, write a short script that simulates rolling two dice 1000 times and prints how many times you rolled a 7. Use random.randint(1,6) for each die and a loop with a counter. Then modify it to set random.seed(42) and confirm you get the same result every time.
Common mistakes
- Calling
random.shuffle()and expecting it to return a new list — it modifies the list in place and returnsNone - Using
random.choice()on an empty list, which raisesIndexError— always check length first - Setting
random.seed()inside a loop and wondering why results are identical — seed once per script - Using
random()for security-critical tasks like password generation — usesecretsmodule instead
Variations
- Use
random.choices()for sampling with replacement (allowing duplicates, unlikesample()) - Use
numpy.randomfor high-performance, vectorized random generation in data science - Use
secretsmodule for cryptographically secure random numbers in security applications
Real-world use cases
- Simulating dice rolls for a board game prototype using
random.randint(1,6) - Randomly selecting winning lottery tickets from a user database with
random.sample(users, k=3) - Shuffling a playlist of songs for a music app using
random.shuffle(song_list)
Key takeaways
- Import
random— it uses the Mersenne Twister pseudorandom generator for all functions - Use
random.random()as the base function for floats in [0.0, 1.0);random.randint(a,b)for integers inclusive - Set
random.seed(value)for reproducible results — essential for testing and debugging random.choice(seq)picks one element;random.sample(seq,k)picks k unique elements without replacementrandom.shuffle(seq)modifies the list in place — make a copy if you need the original order- For security-critical randomness (passwords, tokens), use the
secretsmodule, notrandom
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.