Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

random.choice() returns same value at the same second, how does one avoid it?

I have been looking at similar questions regarding how to generate random numbers in python. Example: Similar Question - but i do not have the problem that the randomfunction returns same values every time.

My random generator works fine, the problem is that it returns the same value when calling the function at, what I think, the same second which is undesireable.

My code looks like this

def getRandomID():
    token = ''
    letters = "abcdefghiklmnopqrstuvwwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
    for i in range(1,36):
        token = token + random.choice(letters)
    return token

As I mentioned this function returns different values when being called at on different times but returns the same value when calling the function at the same time. How do I avoid this problem?

I use this function in a back-end-server to generate unique IDs for users in front-end to insert in a database so I cannot control the time intervals when this happens. I must have random tokens to map the users in the database to be able to insert them correctly with queuenumbers in the database.

like image 952
Axel Ekeberg Avatar asked Sep 21 '15 09:09

Axel Ekeberg


3 Answers

You could possibly improve matters by using random.SystemRandom() as follows:

import random

sys_random = random.SystemRandom()

def getRandomID():
    token = ''
    letters = "abcdefghiklmnopqrstuvwwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
    for i in range(1, 36):
        token = token + sys_random.choice(letters)
    return token

print(getRandomID())

This attempts to use the os.urandom() function which generates random numbers from sources provided by the operating system. The .choices() function could also be used to return a list of choices in a single call, avoiding the string concatenation:

import random

sys_random = random.SystemRandom()

def getRandomID():
    letters = "abcdefghiklmnopqrstuvwwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
    return ''.join(sys_random.choices(letters, k=35))

print(getRandomID())
like image 63
Martin Evans Avatar answered Oct 22 '22 00:10

Martin Evans


def getRandomID(n):

    import datetime
    import random

    random.seed(datetime.datetime.now())

    letters = "abcdefghiklmnopqrstuvwwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

    idList = [ ''.join([random.choice(letters) for j in range(1,36)]) for i in range(n)]

    return idList

this script in the 3rd test of 10 million ids again have made them all unique

changing for loop to list comprehension did speedup quite a bit.

>>> listt = getRandomID(10000000)
>>> print(len(listt))
10000000

>>> setOfIds = set(listt)
>>> print(len(setOfIds))
10000000

this script uses permutations with repetition: 62 choose 35, to theoretically total number of ids is quite big it is pow(62,35)

541638008296341754635824011376225346986572413939634062667808768
like image 20
LetzerWille Avatar answered Oct 22 '22 00:10

LetzerWille


Another option would be to update the seed with the previous result to get a pseudorandom sequence. An option would be old_seed XOR result or just the result.

like image 32
allo Avatar answered Oct 21 '22 23:10

allo