69

Is there any way to find out what seed Python used to seed its random number generator?

I know I can specify my own seed, but I'm quite happy with Python managing it. But, I do want to know what seed it used, so that if I like the results I'm getting in a particular run, I could reproduce that run later. If I had the seed that was used then I could.

If the answer is I can't, then what's the best way to generate a seed myself? I want them to always be different from run to run---I just want to know what was used.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
mix
  • 6,943
  • 15
  • 61
  • 90
  • What is `math.random()`? Do you mean [`random.random()`](http://docs.python.org/library/random.html#random.random)? – ephemient Feb 16 '11 at 04:44
  • since its not easy to get the original seed back, I'd just generate one myself from the os, e.g. `seed = int.from_bytes(os.urandom(8), byteorder="big")` – Charlie Parker Mar 30 '18 at 00:27

7 Answers7

74

It is not possible to get the automatic seed back out from the generator. I normally generate seeds like this:

seed = random.randrange(sys.maxsize)
rng = random.Random(seed)
print("Seed was:", seed)

This way it is time-based, so each time you run the script (manually) it will be different, but if you are using multiple generators they won't have the same seed simply because they were created almost simultaneously.

Zooba
  • 11,221
  • 3
  • 37
  • 40
  • 4
    The PRNG is automatically seeded from the OS's PRNG by default (via `os.urandom`), so this is almost always unnecessary. – Glenn Maynard Feb 16 '11 at 07:00
  • 33
    @Glenn Maynard Unless you want to know what the seed was so you can reproduce the generated sequence later. – Zooba Feb 16 '11 at 09:40
  • 4
    Python is lacking *`random.getseed()`*, but this is much less painful than [the equivalent in Java](http://stackoverflow.com/questions/6001368/how-do-i-get-the-seed-from-a-random-in-java). – smci Feb 09 '12 at 00:10
  • how does your way of seeding compare to: `seed = ord(os.urandom(1))`? – Charlie Parker Mar 30 '18 at 00:03
  • @BrendanMaguire what are you talking about, you can use `sys.maxsize` as far as I could tell in my python `Python 3.6.3 |Anaconda custom (64-bit)| (default, Nov 3 2017, 19:19:16)` one can do `sys.maxsize 9223372036854775807` – Charlie Parker Mar 30 '18 at 00:07
  • @smci that linked example is *far* more verbose than is required here, since this question doesn't require Copyability – scubbo Jun 02 '20 at 00:39
39

The state of the random number generator isn't always simply a seed. For example, a secure PRNG typically has an entropy buffer, which is a larger block of data.

You can, however, save and restore the entire state of the randon number generator, so you can reproduce its results later on:

import random

old_state = random.getstate()
print random.random()

random.setstate(old_state)
print random.random()

# You can also restore the state into your own instance of the PRNG, to avoid
# thread-safety issues from using the default, global instance.
prng = random.Random()
prng.setstate(old_state)
print prng.random()

The results of getstate can, of course, be pickled if you want to save it persistently.

http://docs.python.org/library/random.html#random.getstate

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • That won't reproduce a sequence, it will merely let you continue from where you left off last time. If you want to reproduce the entire sequence from the start, you need to know the seed value. – Zooba Feb 16 '11 at 09:41
  • 10
    @Zooba: Those are equivalent. To reproduce the entire sequence from the tart, simply store the state of the PRNG at that point. – Glenn Maynard Feb 16 '11 at 19:06
  • 9
    Given the context of the question (optional per-run seeding) storing a relatively large state tuple is far from optimal. A single seed value is far more easily embedded in configuration data, and if you need a secure PRNG you shouldn't be saving the seed (or the state) anyway. – Zooba Feb 16 '11 at 20:56
  • 2
    This is technically correct but Zooba's approach is way more user-friendly for the OP's purpose. – smci Feb 09 '12 at 00:07
  • 3
    @smci: His approach is needlessly insecure, massively reducing the amount of randomness available. (And the idea that you shouldn't be storing the state of a secure PRNG is nonsense--you may as well say that you shouldn't store private keys for HTTPS servers.) – Glenn Maynard Feb 21 '12 at 16:49
  • This was massively helpful. My problem was that I (thought I) needed the seed to reproduce a simulation run in the past, so creating a new seed and using that was not an option. This answer solved my problem. – Davoud Taghawi-Nejad Nov 30 '20 at 06:06
22

You can subclass the random.Random, rewrite the seed() method the same way python does (v3.5 in this example) but storing seed value in a variable before calling super():

    import random

    class Random(random.Random):
        def seed(self, a=None, version=2):
            from os import urandom as _urandom
            from hashlib import sha512 as _sha512
            if a is None:
                try:
                    # Seed with enough bytes to span the 19937 bit
                    # state space for the Mersenne Twister
                    a = int.from_bytes(_urandom(2500), 'big')
                except NotImplementedError:
                    import time
                    a = int(time.time() * 256) # use fractional seconds

            if version == 2:
                if isinstance(a, (str, bytes, bytearray)):
                    if isinstance(a, str):
                        a = a.encode()
                    a += _sha512(a).digest()
                    a = int.from_bytes(a, 'big')

            self._current_seed = a
            super().seed(a)

        def get_seed(self):
            return self._current_seed

If you test it, a first random value generated with a new seed and a second value generated using the same seed (with the get_seed() method we created) will be equal:

    >>> rnd1 = Random()
    >>> seed = rnd1.get_seed()
    >>> v1 = rnd1.randint(1, 0x260)
    >>> rnd2 = Random(seed)
    >>> v2 = rnd2.randint(1, 0x260)
    >>> v1 == v2
    True

If you store/copy the huge seed value and try using it in another session the value generated will be exactly the same.

Lucas Siqueira
  • 765
  • 7
  • 19
7

Since no one mentioned that usually the best random sample you could get in any programming language is generated through the operating system I have to provide the following code:

random_data = os.urandom(8)
seed = int.from_bytes(random_data, byteorder="big")

this is cryptographically secure.

Source: https://www.quora.com/What-is-the-best-way-to-generate-random-seeds-in-python


with a value 8 it seems to produce around the same number of digits as sys.maxsize for me.

>>> int.from_bytes(os.urandom(8), byteorder="big")
17520563261454622261
>>> sys.maxsize
9223372036854775807
>>>
Charlie Parker
  • 5,884
  • 57
  • 198
  • 323
5

If you "set" the seed using random.seed(None), the randomizer is automatically seeded as a function the system time. However, you can't access this value, as you observed. What I do when I want to randomize but still know the seed is this:

tim = datetime.datetime.now()
randseed = tim.hour*10000+tim.minute*100+tim.second
random.seed(randseed)

note: the reason I prefer this to using time.time() as proposed by @Abdallah is because this way the randseed is human-readable and immediately understandable, which often has big benefits. Date components and even microsegments could also be added as needed.

Dr. Andrew
  • 2,532
  • 3
  • 26
  • 42
3

I wanted to do the same thing but I could not get the seed. So, I thought since the seed is generated from time. I created my seed using the system time and used it as a seed so now I know which seed was used.

SEED = int(time.time())
random.seed(SEED)
Kampai
  • 22,848
  • 21
  • 95
  • 95
Abdallah Sobehy
  • 2,881
  • 1
  • 15
  • 28
2

The seed is an internal variable in the random package which is used to create the next random number. When a new number is requested, the seed is updated, too.

I would simple use 0 as a seed if you want to be sure to have the same random numbers every time, or make i configurable.

CorelDraw once had a random pattern generator, which was initialized with a seed. Patterns varied drastically for different seeds, so the seed was important configuration information of the pattern. It should be part of the config options for your runs.

EDIT: As noted by ephemient, the internal state of a random number generator may be more complex than the seed, depending on its implementation.

Daniel
  • 27,718
  • 20
  • 89
  • 133
  • 2
    The seed is actually used to create the internal state of the generator. There happen to be many states which are reached by calling `random()` but can not be the direct result of seeding. So it's inaccurate to say that the seed is an internal variable — it merely seeds the initial state. – ephemient Feb 16 '11 at 05:01
  • 1
    Oh, I thought the length of the seed would imply the length of the possible internal states. Thanks for the correction. – Daniel Feb 16 '11 at 05:33