Follow the code.
To see where the random module "lives" on your system, you can simply do this in the terminal:
>>> import random >>> random.__file__ '/usr/lib/python2.7/random.pyc'
This gives you the path to the .pyc file ("compiled"), which is usually located next to the original .py where you can find readable code.
Let's see what happens in /usr/lib/python2.7/random.py :
You will see that he creates an instance of the Random class and then (at the bottom of the file) “promotes” the methods of this instance in the module function. Neat trick. When a random module is imported to any place, a new instance of this Random class is created, then its values are initialized, and the methods are redefined as functions of the module, which makes it rather random during import (er ... or per-python-interpreter-instance).
_inst = Random() seed = _inst.seed random = _inst.random uniform = _inst.uniform triangular = _inst.triangular randint = _inst.randint
The only thing this Random class does in its __init__ method is its __init__ :
class Random(_random.Random): ... def __init__(self, x=None): self.seed(x) ... _inst = Random() seed = _inst.seed
So ... what happens if x is None (seeds not specified)? Ok, let's check this self.seed method:
def seed(self, a=None): """Initialize internal state from hashable object. None or no argument seeds from current time or from an operating system specific randomness source if available. If a is not None or an int or long, hash(a) is used instead. """ if a is None: try: a = long(_hexlify(_urandom(16)), 16) except NotImplementedError: import time a = long(time.time() * 256)
The comments already tell what is happening ... This method tries to use the default random number generator provided by the OS, and if it is not there, it will use the current time as the initial value.
But wait ... What the hell is this _urandom(16) chtoli then?
The answer lies at the beginning of this random.py file:
from os import urandom as _urandom from binascii import hexlify as _hexlify
Tadaaa ... Seed is a 16-byte number coming from os.urandom
Suppose we are in a civilized OS such as Linux (with a real random number generator). The starting number used by the random module is similar to the action:
>>> long(binascii.hexlify(os.urandom(16)), 16) 46313715670266209791161509840588935391L
The reason why specifying the initial value is considered not so big is because random functions are not really "random" ... It's just a very strange sequence of numbers. But this sequence will be the same, given the same seed. You can try it yourself:
>>> import random >>> random.seed(1) >>> random.randint(0,100) 13 >>> random.randint(0,100) 85 >>> random.randint(0,100) 77
No matter when or how, or even where you run this code (as long as the algorithm used to generate random numbers remains unchanged), if your initial coefficient is 1 , you will always get integers 13 , 85 , 77 ... which the view defeats the target (see this on the generation of pseudorandom numbers). On the other hand, there are times when this may be a desirable function.
This is why it is considered "better" to rely on the random number generator operating system. They are usually calculated based on hardware interrupts, which are very, very random (including interrupts when reading from the hard disk, keystrokes typed by the user, moving the mouse ...) On Linux, this OS generator is / dev / random , Or, being a little demanding, /dev/urandom (this is what Python os.urandom actually uses internally) The difference is that (as mentioned earlier) /dev/random uses hardware interrupts to generate a random sequence. If there are no interrupts, /dev/random may be exhausted, and you may have to wait a bit until you get the next random number. /dev/urandom uses /dev/random internal use, but this ensures that random numbers are always ready for it.
If you are using linux, just run cat/dev/random on the terminal (and get ready to press Ctrl + C , because it will really start to output really random things)
borrajax@borrajax :/tmp$ cat /dev/random _+ _ ?zta K q ߤk / qSlV { Gzk' #p$ *C F" B9 o~, QH ɭ f ̬po 2o (= t 0 p|m e - 5 ߁ٵ ED l Qt / ,uD w&m ѩ/ ; 5Ce + M ~ 4D XN ?ס d $7Ā kte▒s ȿ7_ - d| cY- j> b}# W<դ 8 { 1» . 75 c4$3z /̾ ( ( ' k fC_^C
Python uses an OS random number generator or time as a seed. This means that the only place I can imagine the potential weakness of the random Python module is when it is used:
- In an OS without an actual random number generator and
- On a device where
time.time always reports the same time (mostly broken clocks)
If you are concerned about the actual randomness of a random module, you can either go directly to os.urandom or use the random number generator in the pycrypto cryptographic library. This is probably more random. I say more random because ...

Image inspiration came from this other SO answer