chinskiy
chinskiy

Reputation: 2715

random.randint shows different output in Python 2.x and Python 3.x with same seed

I am porting the application from python 2 to python 3 and encountered the following problem: random.randint returns different result according to used Python version. So

import random
random.seed(1)
result = random.randint(1, 100)

On Python 2.x result will be 14 and on Python 3.x: 18

Unfortunately, I need to have the same output on python3 to have backward compatibility of service.

Now I have only working idea of usage subprocess module from Python 3.x to execute Python 2.x code

result = subprocess.check_output(
    '''python2 -c "import random; random.seed('%s'); print(random.randint(1, 100))"''' % seed,
    shell=True
 )

But such an approach is slower approx. in 1000 times than execute just random.randint(1, 100).

Maybe there are other approaches to do this?

Upvotes: 11

Views: 1664

Answers (4)

ToTamire
ToTamire

Reputation: 1703

Functions which emulate random.seed(a=None) and random.randint(a, b) for python 3 and python 2:

import random


def seed(a=None):
    try:  # Python3
        random.seed(a, version=1)
    except TypeError:  # Python2
        random.seed(a)


def randint(a, b):
    return int(random.random() * (b - a + 1)) + a

Use:

seed(1)
result = randint(1, 100)

Upvotes: 0

chinskiy
chinskiy

Reputation: 2715

Finally found the answer!

Sparky05 give interesting idea and was near with int(1+99*random.random()).

But the right answer is

random.seed(seed, version=1)
int(random.random() * 100) + 1

in Python 3.x

Works in the same way like

random.seed(seed)
random.randint(1, 100)

in Python 2.x

Upvotes: 4

Sparky05
Sparky05

Reputation: 4892

The difference is caused by two things:

  1. You should use random.seed(42, version=1)
  2. In python 3.2 there was a change to random.randrange, which is called by random.randint and probably add to above issue.

So use something like:

try: random.seed(42, version=1)  # Python 3
except TypeError: random.seed(42)  # Python 2

and int(1+random.random()*99).

More detail

Backward compatibility was on purpose dropped with the change of randrange, see the original issue.

See this reddit post.

If possible use numpy.randomlike is proposed in the reddit post.

Use of random.seed(42, version=1) as described in the documentation will cause random.random() to deliver the same result but give a different result for random.randint(1,100) (because in python 3.2 some problem with the old implementation was fixed). You may opt to only rely on something like int(1+random.random()*99).

(Python 2 will run out of support very soon, soon2 or here. If possible check, if backward compatibility is really needed.)

My current tests:

import random 

try: random.seed(42, version=1)  # Python 3
except TypeError: random.seed(42)  # Python 2
print(random.random())
print(int(1+99*random.random()))
print(random.randint(1,99))

Results on Python 2

0.639426798458
3
28

and Python 3

0.6394267984578837
3
36

Upvotes: 9

theberzi
theberzi

Reputation: 2645

You can specify which version to use for the seed: random.seed(1, version=1). However, as stated by Sparky05, you are probably better off using numpy.random instead.

Upvotes: 0

Related Questions