Chapters
Python114 chapters

Modules and the standard libraryChapter 78 of 114

Random Numbers

Pick, shuffle and sample, and know when random is not good enough.

The everyday functions

Python
import random

value = random.randint(1, 6)
print(1 <= value <= 6)

print(random.choice(["rock", "paper", "scissors"]) in ["rock", "paper", "scissors"])
print(0 <= random.random() < 1)
print(1 <= random.uniform(1, 2) <= 2)

Output

True
True
True
True

The outputs are checked rather than printed, because they differ every run — and that is the point.

FunctionGives
randint(a, b)a whole number, including both ends
randrange(a, b)a whole number, excluding b, like range
random()a float from 0 up to but not including 1
uniform(a, b)a float between the two
choice(seq)one item
choices(seq, k=n)n items, with repeats
sample(seq, k=n)n items, no repeats
shuffle(list)reorders in place, returns None

With and without repeats

Python
import random

deck = ["a", "b", "c", "d"]

hand = random.sample(deck, 3)
print(len(hand), len(set(hand)))

rolls = random.choices(deck, k=6)
print(len(rolls))
print(set(rolls) <= set(deck))

Output

3 3
6
True

sample gave three different cards. choices can repeat, which is right for dice and wrong for dealing.

Shuffling

Python
import random

deck = [1, 2, 3, 4, 5]
result = random.shuffle(deck)

print(result)
print(sorted(deck))
print(len(deck))

Output

None
[1, 2, 3, 4, 5]
5

shuffle changes the list and returns None, like sort(). To keep the original, use random.sample(deck, len(deck)).

Seeding makes it repeatable

Same seed, same sequence. That is how you test code that uses randomness:

Python
import random

random.seed(42)
first = [random.randint(1, 100) for _ in range(5)]

random.seed(42)
second = [random.randint(1, 100) for _ in range(5)]

print(first == second)
print(len(first), all(1 <= n <= 100 for n in first))

Output

True
5 True

Without a seed, Python seeds from the system clock and entropy, so every run differs.

Weighted choices

Python
import random

random.seed(0)
picks = random.choices(["common", "rare"], weights=[9, 1], k=1000)

print(set(picks) <= {"common", "rare"})
print(picks.count("common") > picks.count("rare"))

Output

True
True

The weights are relative, so [9, 1] means roughly nine to one. They do not have to add up to anything.

Independent streams

random.Random() gives you a generator that nothing else can disturb. Useful when one part of a program seeds for testing and another must not be affected:

Python
import random

a = random.Random(1)
b = random.Random(1)

print([a.randint(1, 100) for _ in range(3)] == [b.randint(1, 100) for _ in range(3)])

Output

True

Not for anything secret

random is a Mersenne Twister. Given enough output, its future values can be predicted, so it must never generate passwords, tokens or keys.

Python
import secrets

token = secrets.token_hex(16)
print(len(token))
print(secrets.choice(["a", "b"]) in ["a", "b"])
print(secrets.randbelow(10) < 10)

Output

32
True
True

secrets has the same shape and uses the operating system's cryptographic source. The rule is simple: if guessing the value would matter, use secrets.

Test yourself

2 questions

What is the difference between randint(1, 6) and randrange(1, 6)?

Show the answer

randint can return 6; randrange cannot — One follows dice and the other follows range. Mixing them up is an off-by-one you will not see in testing.

Which module should generate a password reset token?

Show the answer

secrets — random is predictable from enough output. If guessing the value would matter, use secrets.

Next chapter

File Handling

Open a file safely, in the right mode, with the right encoding.