Python random Module: randint, choice, shuffle, seed and More
Learn the Python random module: random(), randint, choice, choices, sample, shuffle and seed, Monte Carlo simulation, fake test data, secrets and numpy.
Every Diwali, a jewellery shop on MG Road in Indore runs a lucky draw. Customers drop coupons into a big drum, the owner spins it, and a child pulls out one coupon. Nobody can predict which one, and that is the whole point.
Now imagine the shop moves the draw online. There is no drum, so the website needs a fair way to pick one coupon from 4,000 entries. And if a customer complains, the owner would like to replay the draw exactly and show it was honest.
Python's random module is that digital drum. Picking a coupon is random.choice. Pulling out three winners who cannot repeat is random.sample. And replaying the same draw is possible because of a seed, the starting point that fixes the whole sequence of "random" results.
The Python random module is a standard-library module that produces pseudo-random numbers using the Mersenne Twister algorithm, with functions to generate random floats and integers, pick or shuffle items from sequences, and draw from distributions, all reproducible through a seed.
This lesson follows Python datetime, and the two combine nicely for generating test data. Examples target Python 3.12+.
What is the random module in Python?
The module ships with Python, so import random is all you need. Here is the online lucky draw.
import random
entries = ["Aarav", "Diya", "Kabir", "Meera", "Rohan", "Sana", "Tanvi", "Vivaan"]
random.seed(2026)
winner = random.choice(entries)
print("Lucky draw winner:", winner)
random.seed(2026)
print("Replay with the same seed:", random.choice(entries))
others = [e for e in entries if e != winner]
print("Three runners-up:", random.sample(others, 3))Run it several times and you get the same winner every time, because the seed is fixed. Remove both random.seed(2026) lines and the winner changes from run to run.
Why random.seed makes results repeatable
Computers are machines that follow instructions, so they cannot produce truly unpredictable numbers on their own. Instead, random uses a pseudo-random number generator (PRNG): a formula that turns an internal state into a number and then updates the state. The numbers look random and pass statistical tests, but the same starting state always gives the same sequence.
The seed sets that starting state. If you do not call seed(), Python seeds itself from the operating system when the module is imported, so every run differs.
Same seed, same sequence. That is what lets a teammate rerun your analysis and get your exact numbers.
import random
random.seed(42)
first = [random.randint(1, 6) for _ in range(5)]
random.seed(42)
second = [random.randint(1, 6) for _ in range(5)]
print(first, second, first == second)
rng_a = random.Random(7)
rng_b = random.Random(7)
print([rng_a.randint(1, 6) for _ in range(5)])
print([rng_b.randint(1, 6) for _ in range(5)])random.Random(7) creates a separate generator object with its own state. Prefer it in larger programs: one part of the code drawing numbers then cannot disturb the sequence of another part, which can happen when everything shares the global generator.
Generating random numbers: random, uniform, randint and gauss
The module has a function for each common kind of number. The main difference to remember is which end values are included.
| Function | Returns | Range |
|---|---|---|
random() |
float | 0.0 up to, but not including, 1.0 |
uniform(a, b) |
float | between a and b |
randint(a, b) |
int | a to b, both included |
randrange(a, b, step) |
int | a up to b, b excluded, like range |
gauss(mu, sigma) |
float | normal distribution around mu |
import random
random.seed(1)
print(round(random.random(), 4))
print(round(random.uniform(150, 450), 2))
print(random.randint(1, 6))
print(random.randrange(0, 100, 10))
print(round(random.gauss(1450, 200), 1))
rolls = [random.randint(1, 6) for _ in range(6000)]
print({face: rolls.count(face) for face in range(1, 7)})The last line rolls a die 6,000 times. Each face appears close to 1,000 times, but never exactly, which is what fair randomness looks like. Small differences between counts are expected noise, not bias.
Quick check
What does random.randint(1, 6) return?
randint includes both end points, unlike randrange and range.
Picking items: choice, choices, sample and shuffle
Most analytics uses of random involve lists: pick a customer, draw a sample of rows, randomise an order. Four functions cover it, and the key difference is replacement: whether an item can be picked again after it has been picked.
import random
rng = random.Random(10)
menu = ["poha", "jalebi", "samosa", "kachori", "sabudana khichdi"]
print("choice: ", rng.choice(menu))
print("choices:", rng.choices(menu, k=6))
print("weighted:", rng.choices(menu, weights=[50, 30, 10, 7, 3], k=8))
print("sample: ", rng.sample(menu, 3))
queue = list(range(1, 11))
rng.shuffle(queue)
print("shuffled:", queue)
print("shuffle returns:", rng.shuffle(queue))Replacement is the deciding question: can the same item come out twice?
| Function | Picks | Repeats? | Returns |
|---|---|---|---|
choice(seq) |
1 item | not applicable | the item |
choices(seq, weights, k) |
k items | yes | new list |
sample(seq, k) |
k items | no | new list |
shuffle(list) |
all items | no | None (changes the list) |
Weights in choices do not need to add up to 100; they are relative. Here poha is five times as likely as samosa. Note that shuffle returns None; writing queue = rng.shuffle(queue) wipes out your list.
Quick check
You need 3 different winners from a list of 50 names. Which call fits?
sample picks without replacement, so no name can win twice; choices allows repeats.
Simulations and fake test data with random
Two everyday jobs for random in analytics are estimating probabilities and inventing realistic sample data.
Simulating probabilities with Monte Carlo
When a probability is hard to work out on paper, you can estimate it by simulating thousands of trials and counting. This is called a Monte Carlo simulation, and random makes it a few lines of code.
import random
rng = random.Random(99)
trials = 20_000
hits = sum(any(rng.randint(1, 6) == 6 for _ in range(4)) for _ in range(trials))
print("P(at least one six in 4 rolls):", round(hits / trials, 3), "exact:", round(1 - (5 / 6) ** 4, 3))
shared = 0
for _ in range(trials // 4):
birthdays = [rng.randint(1, 365) for _ in range(23)]
shared += len(set(birthdays)) < 23
print("P(shared birthday among 23):", round(shared / (trials // 4), 3))The estimate lands within about a percentage point of the exact answer, and more trials bring it closer. The birthday result, around 50% for only 23 people, surprises most people. The probability for data science tutorial explains why.
Generating fake test data for analysis
Before real data arrives, you often need realistic sample rows to build and test a report. A seeded generator gives you a dataset that is random-looking but identical for everyone on the team.
import random
from datetime import date, timedelta
import pandas as pd
rng = random.Random(42)
cities = ["Indore", "Bhopal", "Ujjain", "Dewas"]
rows = []
for order_id in range(1001, 1011):
rows.append({
"order_id": order_id,
"date": date(2026, 11, 1) + timedelta(days=rng.randint(0, 29)),
"city": rng.choices(cities, weights=[5, 3, 1, 1])[0],
"amount": round(rng.uniform(200, 3000), -1),
})
df = pd.DataFrame(rows)
print(df.to_string(index=False))
print(df.groupby("city")["amount"].sum().to_string())The weights make Indore the most common city, which mirrors a business based there. Random dates come from adding a random number of days to a start date. For drawing statistically sound samples from real data, see sampling techniques.
random vs secrets vs numpy.random
The random module is ideal for simulations and test data, but it is predictable by design: anyone who learns the state can predict every later number. Two other tools cover the cases where that matters.
| Tool | Use it for | Avoid it for |
|---|---|---|
random |
simulations, games, test data, shuffling | passwords, OTPs, tokens |
secrets |
passwords, OTPs, reset links, API tokens | reproducible experiments |
numpy.random.default_rng |
large arrays, fast vectorised sampling | single picks in plain Python |
import secrets
import string
import numpy as np
otp = "".join(secrets.choice(string.digits) for _ in range(6))
print("OTP has", len(otp), "digits:", otp.isdigit())
print("Reset token is plain URL-safe text:", secrets.token_urlsafe(16).isascii())
rng = np.random.default_rng(42)
print(rng.integers(1, 7, size=10))
print(rng.normal(1450, 200, size=3).round(1))
print(rng.choice(["A", "B"], size=8))The secrets output is different on every run and cannot be seeded, which is exactly why it is safe. numpy's generator, by contrast, takes a seed and produces whole arrays at once, which is what pandas and scikit-learn workflows expect. Note that numpy's integers(1, 7) excludes the upper end, unlike randint.
Common mistakes with the Python random module
- Assuming
randint(1, 6)stops at 5. Both ends are included.randrange(1, 6)is the one that excludes 6. - Assigning the result of
shuffle. It changes the list in place and returnsNone. - Seeding inside a loop.
random.seed(1)before every draw returns the same number every time. - Using
randomfor security. Usesecretsfor OTPs, passwords and tokens. - Using
choiceswhen you need unique winners.choicescan repeat;samplecannot. - Forgetting to seed experiments. Results you cannot reproduce are hard to trust or debug.
Key takeaways
randomproduces pseudo-random numbers that are reproducible with a seed.random.Random(seed)gives an independent generator; prefer it in larger code.randintincludes both ends;randrangeexcludes the end, likerange.choicepicks one,choicespicks with replacement and weights,samplepicks without replacement.shufflereorders a list in place and returnsNone.- Monte Carlo simulation estimates probabilities by counting simulated trials.
- Use
secretsfor anything security-related and numpy'sdefault_rngfor arrays.
This completes the Advanced Python section. Put everything together in Python projects for beginners, starting with a simulation game. Seeded test datasets like the one above are how learners in Debugshala's analytics batches in Indore build reports before touching client data.
FAQ
How do I generate a random number in Python?
Import the random module and call the function for the type you need. random.randint(1, 100) gives a whole number from 1 to 100 inclusive, random.random() gives a float from 0 up to 1, and random.uniform(10, 20) gives a float between 10 and 20. Call random.seed() first for repeatable results.
What does random.seed() do in Python?
random.seed(n) sets the starting state of the pseudo-random generator, so the same seed always produces the same sequence of numbers. Data analysts seed simulations, samples and train-test splits so that anyone rerunning the code gets identical results. Without a seed, Python starts from system entropy and each run differs.
What is the difference between random.choice and random.choices?
random.choice(seq) returns one item. random.choices(seq, k=n) returns a list of n items picked with replacement, so items can repeat, and it accepts weights to make some items more likely. If you need several items with no repeats, use random.sample(seq, n) instead.
Is Python's random module truly random?
No. It is pseudo-random: a deterministic algorithm, the Mersenne Twister, produces numbers that look random and are fine for simulations and games. Because the sequence can be predicted from its state, it must not be used for passwords or tokens. For security, use the secrets module, which draws from the operating system's secure source.
Can I learn Python simulations and sampling at Debugshala in Indore?
Yes. Debugshala's data analytics course at Old Palasia covers Python, pandas and the probability ideas behind sampling and simulation, taught in English and Hindi with a free demo class first. To check yourself between sessions, run probability-style Python puzzles on Debugshala Test.
From the team behind this site
Go further with the Data Analytics Course at Debugshala
These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.
- Offline classes at Old Palasia, Indore
- Free demo class before you pay
- Non-IT, fresher and year-gap friendly
- Placement assistance
700+ students placed · 200+ hiring partners · 4.9★ Google rating