Python random Module
In this tutorial, we'll use the random module to generate random numbers, make random choices, shuffle items, and create repeatable test data.
Python's random module generates pseudo-random numbers and makes random selections. It is useful for games, simulations, test data, and shuffling collections.
It is included with Python:
import random
The values are pseudo-random: they are produced by an algorithm. They look unpredictable for ordinary programs, but they are not suitable for passwords, security tokens, or cryptography.
Random floating-point values
random.random() returns a float from 0.0 up to, but not including, 1.0:
import random
value = random.random()
print(value)
Every run will normally print a different value.
Use uniform(a, b) for a float between two limits:
temperature = random.uniform(18.0, 24.0)
print(round(temperature, 1))
Because floating-point values are approximations, do not assume the result has a fixed number of decimal places. Round only when displaying or when the problem specifically requires it.
Random integers
randint(a, b) includes both endpoints:
import random
dice_roll = random.randint(1, 6)
print(dice_roll)
randrange() follows the same start, stop, and step rules as range():
even_number = random.randrange(2, 11, 2)
print(even_number)
Possible results are 2, 4, 6, 8, and 10. The stop value itself is excluded, just as it is with range().
Choosing one item
Use choice() to select an item from a non-empty sequence:
import random
topics = ["lists", "functions", "classes"]
topic = random.choice(topics)
print(topic)
Calling choice([]) raises IndexError, so handle an empty sequence when it is possible:
topic = random.choice(topics) if topics else None
Choosing several items
sample() chooses unique items without replacement:
import random
names = ["Ada", "Grace", "James", "Linus"]
winners = random.sample(names, k=2)
print(winners)
No name can appear twice. k cannot be larger than the population.
choices() samples with replacement, so duplicates are possible:
colours = ["red", "green", "blue"]
draws = random.choices(colours, k=5)
print(draws)
It also supports weights:
status = random.choices(
["success", "failure"],
weights=[9, 1],
k=1,
)[0]
Weights express relative likelihood; they do not guarantee an exact ratio over a small number of calls.
Shuffling a list
shuffle() changes a list in place:
import random
cards = ["A", "K", "Q", "J"]
random.shuffle(cards)
print(cards)
It returns None. This is incorrect:
cards = random.shuffle(cards)
After that assignment, cards would be None.
To preserve the original list, copy it first:
shuffled_cards = cards.copy()
random.shuffle(shuffled_cards)
Repeating results with a seed
A seed makes a pseudo-random sequence repeatable:
import random
random.seed(42)
print(random.randint(1, 100))
print(random.randint(1, 100))
This is helpful in tests and debugging. It is usually undesirable in a game where each run should differ.
Avoid changing the module's global random state inside reusable functions. Create a dedicated generator instead:
import random
def repeatable_choice(items, seed):
generator = random.Random(seed)
return generator.choice(items)
print(repeatable_choice(["a", "b", "c"], 42))
print(repeatable_choice(["a", "b", "c"], 42))
Both calls return the same result, and other code using random is unaffected.
Generating random test data
You can combine random functions with comprehensions:
import random
generator = random.Random(7)
scores = [generator.randint(0, 100) for _ in range(10)]
print(scores)
Using a dedicated seeded generator makes a failed test case reproducible.
Randomness for security
Do not use random to create passwords, reset links, API keys, or session tokens. Its output can be predictable to an attacker.
Use the secrets module instead:
import secrets
token = secrets.token_urlsafe(32)
print(token)
For secure choices:
colour = secrets.choice(["red", "green", "blue"])
A practical example: roll several dice
import random
def roll_dice(count, sides=6, *, generator=None):
if count < 0:
raise ValueError("count cannot be negative")
if sides < 2:
raise ValueError("a die needs at least two sides")
rng = generator or random
return [rng.randint(1, sides) for _ in range(count)]
test_generator = random.Random(10)
print(roll_dice(3, generator=test_generator))
Accepting a generator keeps normal usage convenient while allowing deterministic tests.
Common random mistakes
- Using
randomfor security-sensitive values. - Forgetting that
randint()includes both endpoints. - Forgetting that
randrange()excludes its stop value. - Assigning the result of
shuffle(), which is alwaysNone. - Asking
sample()for more unique items than exist. - Calling
choice()with an empty sequence. - Re-seeding before every call, which can repeatedly produce the same values.
- Writing tests that sometimes fail because their random input is not reproducible.
Practice
1. Simulate rolling two six-sided dice and return their total. 2. Select three unique quiz questions from a list. 3. Shuffle a copy of a list without changing the original. 4. Produce the same five random integers whenever a supplied seed is reused. 5. Explain why a password generator should use secrets, not random.
Try related tasks in the [interactive Python coding exercises](/codingexercises).