random.seed

Same seed in, same numbers out, on every platform. An int seed is used by its absolute value, a str or bytes seed is hashed with SHA-512 into an int, and no seed at all means fresh entropy from the operating system.

random functionAll Python 3 versions (str seeding version 2 since 3.2, type check since 3.11)Live demo
Common call
random.seed(42)
Returns
None (it changes the generator state)
Replaces
Saving the numbers you drew to replay a run
Watch out
seed('42') and seed(42) give different sequences
random.seed(aa — None: seed from os.urandom() (or the time if unavailable). int: its absolute value, all bits used. str/bytes/bytearray: the bytes plus their SHA-512 digest, read as one int. float: its hash(). Anything else raises TypeError (3.11+).type: None | int | float | str | bytes | bytearray · default: None=None, versionversion — Only affects str and bytes seeds: 1 reproduces the narrower seeding of Python 2 / before 3.2.type: int · default: 2=2)
→ None

Demo

Live evaluation
Seed, draw three numbers, seed again with the same value, draw again: the lists are identical.
Try:
Inputs
seedint | stran int or a string
Code
import random
random.seed(42)
a = [random.randint(1, 100) for _ in range(3)]
random.seed(42)
b = [random.randint(1, 100) for _ in range(3)]
(a, b, a == b)
Result
([82, 15, 4], [82, 15, 4], True)

seed(42) and seed(-42) produce the same 0.6394267984578837: the C code takes abs() of an int before splitting it into 32-bit words for the Mersenne Twister. A string goes through SHA-512 first, so "hello" and "Hello" land on unrelated states. A float is seeded by its hash(): 1.5 is not 1 or 2, but seed(42.0) equals seed(42) because hash(42.0) == 42.

Parameters

NameTypeRequiredDescription
aNone | int | float | str | bytes | bytearrayno (None)None: seed from os.urandom() (or the time if unavailable). int: its absolute value, all bits used. str/bytes/bytearray: the bytes plus their SHA-512 digest, read as one int. float: its hash(). Anything else raises TypeError (3.11+).
versionintno (2)Only affects str and bytes seeds: 1 reproduces the narrower seeding of Python 2 / before 3.2.

Return value

None — Nothing; the generator state is replaced and the cached gauss() value is cleared.

Common patterns

Seed from the command line or config
Values arrive as text: convert to int, or the str seed gives a different sequence.
import random
import sys
random.seed(int(sys.argv[1]) if len(sys.argv) > 1 else None)
Seeded test fixture
A dedicated Random keeps the test reproducible without touching the global generator.
import random
def make_users(n, seed=0):
    rng = random.Random(seed)
    return [rng.randint(18, 90) for _ in range(n)]
Log the seed you used
Draw a seed, print it, then seed with it: any surprising run can be replayed later.
import random
import secrets
run_seed = secrets.randbits(32)
print(f'seed = {run_seed}')
random.seed(run_seed)

Examples

1. Seed, then draw
import random random.seed(42) [random.random() for _ in range(3)]
Returns
[0.6394267984578837, 0.025010755222666936, 0.27502931836911926]
2. A negative int seeds like its abs()
import random random.seed(-42) [random.randint(1, 100) for _ in range(3)]
Returns
[82, 15, 4]
3. The str '42' is a different seed
import random random.seed('42') [random.randint(1, 100) for _ in range(3)]
Returns
[61, 59, 82]
4. bytes seed like the same str
import random random.seed(b'42') [random.randint(1, 100) for _ in range(3)]
Returns
[61, 59, 82]
5. A float seed uses hash()
import random random.seed(42.0) [random.randint(1, 100) for _ in range(3)]
Returns
[82, 15, 4]
6. seed() returns None
import random print(random.seed(42))
Returns
None
7. Only a few types are accepted
import random random.seed([1, 2, 3])
Returns
TypeError: The only supported seed types are: None, int, float, str, bytes, and bytearray.

Pitfalls

1. Seeding inside the loop
Every seed() restarts the sequence, so re-seeding before each draw returns the same "random" value again and again. Seed once, before the loop.
seed per draw
import random
rolls = []
for _ in range(3):
    random.seed(42)
    rolls.append(random.randint(1, 6))
rolls
[6, 6, 6]
seed once
import random
random.seed(42)
rolls = []
for _ in range(3):
    rolls.append(random.randint(1, 6))
rolls
[6, 1, 1]
2. A seed read as text
Seeds from sys.argv, environment variables or JSON strings are str. seed('42') hashes the text, so it does not reproduce a run that used seed(42).
str seed
import random
seed_text = '42'
random.seed(seed_text)
[random.randint(1, 100) for _ in range(3)]
[61, 59, 82]
int(seed)
import random
seed_text = '42'
random.seed(int(seed_text))
[random.randint(1, 100) for _ in range(3)]
[82, 15, 4]

When to use

Use it
  • Reproducible simulations, tests and bug reports
  • Demos and tutorials whose output must match the text
  • Re-randomizing from the OS: random.seed() with no argument
Reach for something else
  • Making anything secret: a known seed means known output → secrets
  • Library code: seeding the shared global generator changes it for every other module → use random.Random(seed)
  • Reproducing NumPy results: numpy.random has its own, separate generators

Notes

CPython impl
random.py converts str/bytes (version 2: int.from_bytes(a + sha512(a).digest())) and checks the type; _random.Random.seed in Modules/_randommodule.c takes abs() of an int, hash() of anything else, splits it into 32-bit words and runs the Mersenne Twister init_by_array()
Errors
TypeError for other types since 3.11; the message wording changed in 3.13 (3.12 starts "The only supported seed types are: None,")
gauss() cache
seed() also clears the second value gauss() keeps for its next call, so seeding fully resets gauss() too
Random.seed
The module function is the bound method of a hidden Random instance; rng.seed(x) does the same for your own instance

FAQ

It resets the generator's internal state from the value you give. After random.seed(42) the sequence of random(), randint(), choice() and so on is always the same, so a run can be reproduced exactly.