Setting Seeds for Reproducible Randomness
random.random() generates a pseudorandom float in the range [0.0, 1.0), inclusive of 0.0 but exclusive of 1.0
Why Random Output Can Repeat
A value produced by random.random() looks unpredictable, but it is not produced without a process. Each call returns the next value in a deterministic sequence based on the random module's internal state. Different runs generally produce different sequences unless you set a seed with random.seed() before calling random.random().
Random-looking does not mean unreproducible. Setting the same seed before the same calls produces identical sequences.
The Value Each Call Returns
random.random() generates a pseudorandom float in the range [0.0, 1.0). The word pseudorandom describes a value that appears random while belonging to a deterministic sequence controlled by the random module's internal state.
The notation [0.0, 1.0) means that 0.0 is included and 1.0 is excluded. A call can return exactly 0.0, but it will never return exactly 1.0.
The range can be scaled. Multiplying a generated value by 100 gives a float in [0.0, 100.0). Multiplying by 6 and converting to an integer gives one of 0, 1, 2, 3, 4, or 5, which can be useful for simulating a die roll.
Following the Generator Through a Loop
A loop is a straightforward way to observe random.random(). If the loop calls the function 10 times, it prints 10 random floats, one per iteration. Every value is in [0.0, 1.0), but the exact values depend on the random module's internal state and can differ from values seen in another run.
Tracing Three Calls
Imagine a loop that calls random.random() three times.
First iteration: The first call returns the next float determined by the random module's current internal state.
Second iteration: The second call returns a new float. The internal state has changed because the first call occurred.
Third iteration: The third call returns the next float in the sequence after the second call, and the internal state advances again.
The loop produces three floats. Each call is a separate event, and the next value depends on the state left by the preceding call.
What do you think happens?
If the same code is run twice without resetting the seed, should you expect the two runs to produce identical sequences?
Reveal answer
Answer: No, because the random module's state is not reset.
The source material states that running the same code twice without resetting the seed produces different sequences. Setting the same seed before both runs produces identical sequences.
Reproducing a Sequence
To reproduce an exact sequence, set the seed with random.seed() before the sequence of random.random() calls begins. When the same seed is set before the same sequence of calls, the random module starts from the corresponding same state and produces identical values in the same order.
| Setup | Expected sequence behavior |
|---|---|
| Same seed before the same calls | Identical sequences |
| No seed reset between runs | Different sequences can occur |
| Different seed | The sequence can differ |
| Different number of earlier random calls | Later output can differ because the internal state differs |
How setup affects reproducibility
Finding the Divergence Point
When actual output differs from an expected sequence, locate the first random.random() call that returned a different value. That is the divergence point. The difference comes from the random module having a different internal state, which can happen when the seed was not set, a different seed was used, or a different number of random calls occurred before the code ran.
Comparing Expected and Actual Values
Suppose five expected values are [0.1, 0.2, 0.3, 0.4, 0.5], while the observed values are [0.7, 0.8, 0.9, 0.6, 0.5]. Where does the sequence first diverge?
Compare the first call: The expected first value is 0.1, but the observed first value is 0.7.
Mark the divergence: The first call to random.random() is the divergence point because it produced a different value immediately.
Interpret the cause: The random module's internal state was different from the state that produced the expected sequence.
The divergence occurred at the first random.random() call. Reproducing the expected sequence requires setting the same seed that produced it previously.
Assuming a random-looking value is unrelated to previous calls.
The random module maintains internal state, and each call returns the next value in a deterministic sequence based on that state.
Fix:
Trace each call in order and remember that every call advances the internal state.Expecting identical output from repeated runs without resetting the seed.
The source states that runs without resetting the seed produce different sequences.
Fix:
Set the same seed before both sequences when reproducible output is needed.Treating 1.0 as a possible result.
The interval uses a parenthesis at 1.0, so the upper bound is exclusive.
Fix:
Read [0.0, 1.0) as including 0.0 and excluding 1.0.Searching for the divergence somewhere after the generated value.
The divergence occurs at the call where the pseudorandom value is generated.
Fix:
Compare expected and actual values in order and identify the first differing random.random() call.
Check Your Understanding
A loop calls random.random() three times. Explain what happens to the random module's internal state after each call, state the valid range for each returned value, and describe what you would change to make a second run reproduce the first run's sequence.
Hints
- Each call returns the next value in the sequence.
- The range includes 0.0 and excludes 1.0.
- Use random.seed() before the loop, using the same seed before both runs.
Key Takeaways
- random.random() returns a pseudorandom float in [0.0, 1.0).
- The lower bound 0.0 is included, while the upper bound 1.0 is excluded.
- Every call returns the next value and advances the random module's internal state.
- The same seed before the same calls produces the same sequence.
- When output differs from expectation, find the first random.random() call where the values diverge.
Key Takeaways
- random.random() generates pseudorandom floats from 0.0 inclusive up to, but not including, 1.0.
- Repeated calls move through a deterministic sequence controlled by the random module's internal state.
- Setting the same seed before repeated runs makes their sequences reproducible.
- The first differing random.random() call marks the divergence point during debugging.