Seeding Python's PRNG with a tuple

614 Views Asked by At

I notice that if I seed Python's PRNG with a tuple, I get different results each time I do it. That is, the Python 3.4 program:

import random
seed1 = ('Foo', 'Bar')
random.seed(seed1)
print(random.random())

prints a different number each time it is run. Is this because the seed taken is the id of the tuple seed1 which is different each time?

What is the best way to use a tuple as a seed to the PRNG so that I get repeatable results? Is it simply random.seed(str(seed1))?

2

There are 2 best solutions below

2
Hooked On

From a previous question:

For Python 3.3+, as @gnibbler pointed out, hash() is randomized between runs. It will work for a single run, but almost definitely won't work across runs of your program (pulling from the text file you mentioned).

So using python 2.x, running hash('Foo', 'Bar') will generally return the same result on the same computer each time which gives you the same initial seed. On python 3.3+ running hash against your tuple gives you a unique value each time.

If you want to have a consistent result with python 3.3+ look into hashlib. For example:

import hashlib
import random

seed1 = ('Foo', 'Bar')
text  = u''.join(seed1).encode('utf-8')
sha   = hashlib.sha1(text)
random.seed(sha.hexdigest())
print(sha.hexdigest())
print(random.random())

> python3 random2.py 
eb8fc41f9d9ae5855c4d801355075e4ccfb22808
0.738130097774164
> python3 random2.py 
eb8fc41f9d9ae5855c4d801355075e4ccfb22808
0.738130097774164

> python2 random2.py 
eb8fc41f9d9ae5855c4d801355075e4ccfb22808
0.628422839243
> python2 random2.py 
eb8fc41f9d9ae5855c4d801355075e4ccfb22808
0.628422839243

i.e. you'll have a consistent seed, but since the random modules differ in their implementation you still get a different random number.

0
dawg On

Interesting.

If you do this:

def repeatable_random(seed):
    random.seed(seed)
    while True:
        yield random.random()

for i, v in zip(range(20), repeatable_random(('Foo', 'Bar'))):
    print((i,v))

You get different values for the random series each time you run it.

If you do this:

def repeatable_random(seed):
    random.seed(repr(seed))      # Note 'repr' here
    while True:
        yield random.random()

for i, v in zip(range(20), repeatable_random(('Foo', 'Bar'))):
    print((i,v))

It is the same series 1=>n on different run of the Python interpreter.