secrets.SystemRandom.seed() Silently Does Nothing (tested)
secrets.SystemRandom is a subclass of random.Random, so it inherits a .seed() method that looks like it should work the same way: pass the same seed, get the same sequence back, useful for reproducible tests. We measured calling it, and it accepts the call without complaint while doing nothing at all.
1. Reseeding SystemRandom to the same value gives different results every time
import secrets
sr = secrets.SystemRandom()
sr.seed(42)
a = sr.random()
sr.seed(42)
b = sr.random()
print(a == b, a, b)
False 0.8598569534391595 0.1470295256972317
Measured: calling seed(42) twice and comparing the very next random() call each time gives two different numbers. No exception, no warning -- the call to seed() simply has no effect. SystemRandom pulls every value straight from the operating system's entropy source (os.urandom()), which is exactly what you want for security-sensitive randomness, but it means there's no internal state for a seed to set.
2. The same test against random.Random shows what "working" looks like
import random
r = random.Random()
r.seed(42)
c = r.random()
r.seed(42)
d = r.random()
print(c == d, c, d)
True 0.6394267984578837 0.6394267984578837
Measured: plain random.Random gives the identical value both times, because its seed() actually resets internal state. This is the behavior a developer reaching for secrets.SystemRandom for "test the same code path with cryptographically strong randomness, but deterministically" would reasonably expect -- and it's exactly what doesn't happen, since the two classes share a method name and signature but not a working contract for it.
3. Inconsistent failure modes: getstate() raises, seed() doesn't
import secrets
sr = secrets.SystemRandom()
sr.getstate()
Traceback (most recent call last):
...
NotImplementedError: System entropy source does not have state.
Measured: getstate() correctly tells you it's unsupported by raising NotImplementedError. seed() does not get the same treatment -- it's inherited unchanged from random.Random and silently accepts any argument, including no argument at all, without ever touching the underlying OS entropy source. If you need deterministic, repeatable output for tests, use a seeded random.Random() instance instead and reserve secrets.SystemRandom (or the plain secrets module functions) for anything that actually needs to be unpredictable.
Frequently asked questions
Does secrets.SystemRandom().seed(42) make the output reproducible?
No -- we measured this directly: calling seed(42) twice in a row and comparing the next random() call each time gave two different values, with no error raised at all.
Why doesn't secrets.SystemRandom.seed() raise an error if it doesn't work?
SystemRandom inherits seed() from random.Random unchanged, so the method exists and accepts arguments -- it's just that SystemRandom pulls values from the OS entropy source (os.urandom()) instead of from seedable internal state, so there's nothing for seed() to set. We confirmed this contrasts with getstate(), which does raise NotImplementedError on SystemRandom.
How can I tell if my 'seeded' SystemRandom test is actually deterministic?
Do what we did: call seed(N), record a value, call seed(N) again, and compare. If the two values differ, the seed isn't having any effect -- which is exactly what we measured for every SystemRandom instance.
What should I use instead of secrets.SystemRandom for reproducible tests?
Use a seeded random.Random() instance, which we confirmed gives identical output across reseeds to the same value. Reserve secrets.SystemRandom and the secrets module's own functions (token_hex, choice, etc.) for randomness that actually needs to be unpredictable, like tokens or passwords.
Is secrets.SystemRandom a subclass of random.Random?
Yes -- that's exactly why this is surprising. It inherits the full random.Random API, including seed() and the distribution methods, but overrides the underlying byte source to use OS entropy, which silently breaks the seeding contract those inherited methods imply.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in secrets module: called secrets.SystemRandom().seed(42) twice in a row and compared the next random() call each time, against the same pattern on random.Random() for contrast, then checked SystemRandom.getstate() for comparison. PlainHeaders is our extension; Python's secrets module is built in.