Generate Random Numbers in Python: randint, choice, seed
Python's random module covers seven functions used in placement tests and projects. Covers randint, choice, sample, shuffle, uniform, seed, and the secrets module.
Python’s random module gives you a clean, one-import path to pseudo-random floats, integers, and list operations: the exact toolkit that appears in placement coding rounds and simulation problems.
The module is part of the Python standard library. No additional install required.
import random
The default generator is the Mersenne Twister, a 32-bit pseudo-random algorithm that passes standard statistical tests. It is not cryptographically secure, but it is more than adequate for dice simulations, data sampling, quiz shuffles, and Monte Carlo exercises. The Python random module documentation covers the full API; this article focuses on the seven functions that matter most for placement tests and project work.
What random gives you
Seven functions cover almost every use case:
| Function | Returns | Typical use |
|---|---|---|
random.random() | float in [0, 1) | Probability gates |
random.uniform(a, b) | float in [a, b] | Continuous ranges |
random.randint(a, b) | int, both ends inclusive | Dice rolls, index picks |
random.randrange(start, stop, step) | int, stop exclusive | Range-based picks |
random.choice(seq) | one element from sequence | Single pick from list |
random.sample(seq, k) | list of k unique elements | Draw without replacement |
random.shuffle(seq) | None, modifies in place | Randomise order |
The distinction between randint and randrange causes the most wrong answers in placement coding tests, out of all the items in this table. That comparison gets its own section below.
Float randomness: random() and uniform()
random.random() returns a float f where 0 <= f < 1. The left boundary is closed; the right is open. Every call produces a different value from the previous one (unless you fix the seed, covered later).
import random
print(random.random()) # e.g. 0.7324159821
print(random.random()) # different value, same session
random.uniform(a, b) stretches that range to any two bounds. The return value is a + (b - a) * random(), so both endpoints are reachable.
import random
# Float between 5 and 10
sensor_reading = random.uniform(5, 10)
print(sensor_reading) # e.g. 7.841326409
Both functions appear in simulation problems and probability exercises, particularly in the numerical-aptitude and coding sections of campus recruitment tests for CSE and ECE students.
Integer randomness: randint vs randrange
This is the section that fixes the most placement test wrong answers.
random.randint(a, b) — both ends inclusive
random.randint(a, b) returns a random integer N where a <= N <= b. Both endpoints are included in the possible output.
import random
# Simulates one roll of a fair six-sided die
roll = random.randint(1, 6)
print(roll) # can be 1, 2, 3, 4, 5, or 6
Writing random.randint(1, 5) to simulate a six-sided die is wrong. It will never return 6. That mistake accounts for a significant portion of logic errors in placement test coding submissions.
random.randrange(start, stop, step) — stop is exclusive
random.randrange(start, stop, step) behaves like Python’s range(): the stop value is excluded from the output.
import random
# Returns 1, 2, 3, 4, or 5 — does NOT return 6
print(random.randrange(1, 6))
# Returns 0, 3, 6, 9, 12, 15, or 18 — not 20
print(random.randrange(0, 20, 3))
Side-by-side comparison (same distribution, different syntax):
| Call | Possible outputs |
|---|---|
random.randint(1, 6) | 1, 2, 3, 4, 5, 6 |
random.randrange(1, 7) | 1, 2, 3, 4, 5, 6 |
random.randrange(1, 6) | 1, 2, 3, 4, 5 |
random.randrange(6) | 0, 1, 2, 3, 4, 5 |
randint(1, 6) and randrange(1, 7) produce the same distribution. If you remember only one thing from this section, make it that equivalence.
Picking and rearranging lists: choice, sample, shuffle
These three functions all work on sequences. The differences in mutability and replacement behaviour matter when writing correct code quickly under exam conditions.
random.choice(seq)
Picks and returns one element at random. The original sequence is unchanged.
import random
cities = ["Chennai", "Hyderabad", "Pune", "Bangalore", "Coimbatore"]
print(random.choice(cities)) # e.g. "Pune"
print(cities) # unchanged
random.sample(seq, k)
Returns a new list of k unique elements drawn from seq. Non-destructive: the original sequence is not modified. Raises ValueError if k > len(seq).
import random
candidates = ["Arjun", "Priya", "Kiran", "Meena", "Ravi", "Divya"]
shortlist = random.sample(candidates, 3)
print(shortlist) # e.g. ['Meena', 'Arjun', 'Divya']
print(candidates) # unchanged: all six names still present
Use sample when you need draw-without-replacement semantics: picking interview slots, assigning test questions, or selecting a random subset of records. For related list-processing patterns, summing elements in a Python list shows how to combine iteration with list operations cleanly.
random.shuffle(seq)
Shuffles the list in place. Returns None. If you need the original order preserved, copy before shuffling.
import random
questions = [1, 2, 3, 4, 5]
random.shuffle(questions)
print(questions) # e.g. [3, 1, 5, 2, 4]
import random
# Preserve the original
original = [10, 20, 30, 40, 50]
shuffled = original.copy()
random.shuffle(shuffled)
print(original) # [10, 20, 30, 40, 50] — unchanged
print(shuffled) # e.g. [40, 10, 50, 20, 30]
The in-place mutation is the most frequent source of bugs when students assign random.shuffle(mylist) to a variable and then print that variable: the variable holds None, not the shuffled list.
Reproducibility with seed() and when to use secrets
random.seed() for consistent output
Every call to the random module draws from the Mersenne Twister’s internal state. random.seed(n) resets that state to a fixed starting point. The same seed produces the same sequence on the same Python version.
import random
random.seed(42)
print(random.randint(1, 100)) # always 82 with seed 42, CPython 3.x
print(random.randint(1, 100)) # always 15
print(random.randint(1, 100)) # always 4
Use cases for seed():
- Unit-testing functions that call
random(fix the seed insetUp, assert the expected result) - Reproducing a specific edge case that appeared during one run
- Generating a deterministic dataset for a classroom exercise or interview demo
Without seed(), each program run produces a different sequence. That’s the correct behaviour for games and simulations; it’s inconvenient for debugging.
When to use secrets instead
For anything security-sensitive, the Mersenne Twister’s predictability is a liability. The Python secrets module uses OS-level randomness and is suitable for generating passwords, tokens, and OTPs.
import secrets
# 6-digit OTP
otp = secrets.randbelow(1000000)
print(f"{otp:06d}") # e.g. 047832
# 32-character hex token (for API keys, session tokens)
token = secrets.token_hex(16)
print(token) # e.g. 'b4b4b8a1c3f40d9e2a5f...'
The decision is straightforward: if the output protects a resource (a login session, a payment, an account), use secrets. If it drives a simulation, a quiz shuffle, or a Monte Carlo run, random is the right tool.
The seed() discipline (fixing one variable at a time to isolate its effect) carries directly into LLM experiment work. TinkerLLM (₹299 entry) is built around that same methodology: fix the prompt structure, vary the temperature parameter, measure the output delta. If random.sample() already feels natural in your code, the jump to calling LLM APIs in Python is a smaller step than it looks. The Python programs for practice collection is a good place to build the broader Python fluency before taking that step. For structuring interactive programs with user input, the Python calculator program walkthrough is a practical companion.
Primary sources
Frequently asked questions
Does random.randint(1, 6) include 6 in its output?
Yes. random.randint(a, b) is inclusive on both ends, so randint(1, 6) can return 1, 2, 3, 4, 5, or 6. This is different from range(1, 6), which stops at 5.
What is the difference between random.random() and random.uniform()?
random.random() returns a float in the half-open interval [0, 1). random.uniform(a, b) stretches that to any range, returning a float between a and b inclusive on both ends.
When should I use the secrets module instead of random?
Use secrets for anything security-critical: passwords, API tokens, session keys, OTP generation. The random module uses Mersenne Twister, which is not cryptographically secure.
How do I shuffle only part of a list in Python?
random.shuffle() shuffles the entire list in place. To shuffle a sub-list, use random.sample() on the slice and assign back: lst[2:5] = random.sample(lst[2:5], 3).
Is Python's random module thread-safe?
The module-level functions share a single global Random instance, which is not thread-safe. For multi-threaded code, create a separate random.Random() instance per thread.
A self-paced playground for building with LLMs.
TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.
Try TinkerLLM (₹299 launch)