Introduction
Even for someone not interested in computer programming, the usefulness of generating random numbers in certain circumstances is something obvious. In most board games we throw dice to generate an unpredictable number that defines the player's next move. Also, we can all agree that playing any card game would be pointless without a proper shuffle between rounds.
But random numbers are not only important in relatively trivial fields like entertainment or gambling. They're especially crucial in the field of cryptography. In order to ensure safe transmission of data, every time a secure connection is necessary, a random key has to be generated. Many different kinds of electronic communication use this kind of security. It's very important for the key to be difficult to guess - the best way to ensure that is by making it random since the moment someone guesses the key, they are able to decipher the message - and the communication is not secure anymore.
True Randomness vs Pseudo-randomness
Random numbers can be obtained as a result of applying methods called random number generators (RNG), which can be divided into two categories: true random-number generators (TRNGs – also called hardware random number generators) and pseudo-random number generators (PRNGS).
True Random Number Generators
The true random number generators are methods which derive randomness, or unpredictability, from unpredictable aspects of physical processes. These methods do not directly produce numbers, but rather states, that can then be interpreted as numbers – this is why they are usually called random event generators (REGs). Some of them, which use macroscopic events, are commonly known – methods like throwing dice, flipping coins or shuffling cards.
These true random number generators often use more complicated physical phenomena. Some of them, like radioactive decay, thermal noise or radio noise, derive their unpredictability from peculiarities of quantum mechanics. Other methods use the unpredictability of atmospheric noise or even the behavior of lava lamps.
Pseudo Random Number Generators
The truth is, very often generating numbers that are actually, truly random, is not necessary. In many cases, all we need are sets of numbers that seem random. This kind of data can be derived from pseudo-random number generators. These are algorithms that use a tiny portion of information (called a seed) and then apply complicated mathematical formulas in order to generate deterministic sets of numbers resembling truly random sets. The seed may be a value derived from a true random number generator, or another source, like the system's clock or the current datetime.
Running the generator multiple times using the same seed will result in the same output every time. The resulting numbers are mostly unrecognizable from numbers derived from true random number generators, although there actually are some hidden regularities in their distribution. Still, for many applications, this kind of deterministic pseudo-randomness is absolutely sufficient.
Python Random Module
Python, obviously offers a super easy-to-use toolkit to handle random numbers. A module, for some reason called random
, implements a pseudo-random number generator, and contains methods that let us directly solve many different programming issues where randomness comes into play.
The random
module is based on Marsenne Twister - a very popular algorithm, which is the default pseudo-random number generator not only for Python, but also for many other popular software systems such as Microsoft Excel, MATLAB, R, or PHP. Its important advantages include permissive licensing, random-likeness confirmed by many statistical tests, and relatively high speed compared to other PRNGs.
The random() Method
The most important method of the random
module is the random()
method. Most of the other functions depend on it. The random()
method generates a random float in range (0.0, 1.0).
>>> import random
>>> random.random()
0.8474337369372327
The seed() Method
If we don't set a seed for our pseudo-random number generation, the default seed is the current system time. However, we can set the exact value of the seed manually - which comes in handy especially if we want to replicate our pseudo-random results in the future. For this purpose, we can use the random.seed()
method.
>>> random.seed(5)
>>> random.random()
0.6229016948897019
>>> random.random()
0.7417869892607294
>>> random.random()
0.7951935655656966
>>> random.seed(5)
>>> random.random()
0.6229016948897019
The random.seed()
method influences all methods of the random
module that we use after calling it. In the example shown above, we set the seed to 5
and then execute the random.random()
function multiple times. It is important to note that the user-defined seed is used only the first time another random
method is executed - after that, the seeds for the following methods are modified using the previously generated random values.
This lets Python come up with new numbers every time. But still, after re-setting the seed using the random.seed()
method, we can reproduce the exact same sequence of pseudo-random numbers at any time. This is very useful for things like running tests. If you give the same seed every time you run a test that uses one of random
's methods then you will still be able to know what the output should be for the tests.
Other Examples of the random Module
The random.random()
method, which gives us a random float value from a certain range, would be enough even for an inexperienced Python developer to design any kind of random-based manipulations around it. You can probably imagine throwing in an if
or two to write a function that randomly draws value from a list or returns a random integer instead of a float. Well, the random
module lets us take care of those tasks automatically as well. Below, I show a couple of cool methods that simplify common randomized operations. You can get to know the entire potential of the random
module in Python's official documentation.
>>> random.randint(1,10)
4
The random.randint()
method takes two arguments describing the range from which the method draws a random integer.
>>> random.randrange(2,10,2)
2
>>> random.randrange(2,10,2)
4
>>> random.randrange(2,10,2)
8
>>> random.randrange(2,10,2)
6
In the script above, the random.randrange()
method is similar to random.randint()
but it also lets us define the third argument, which is the step point of the defined range. In the example above, we only require even numbers from a range between 2 and 10.
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
>>> cards = ['ace_spades','10_hearts','3_diamonds','king_hearts']
>>> random.choice(cards)
'10_hearts'
In the above script, the random.choice()
method picks a random element from a list.
>>> cards = ['ace_spades','10_hearts','3_diamonds','king_hearts']
>>> random.shuffle(cards)
>>> print(cards)
['king_hearts', '3_diamonds', 'ace_spades', '10_hearts']
In the previous script, the random.shuffle()
method shuffles a list of elements. It is important to note that it alters the list in-place - which means it returns None
and actually modifies our cards
variable.
Conclusions
Getting good random numbers, for serious applications such as cryptography, is not an easy task. But when a solid, pseudo-random number is sufficient for our application, Python, as always, comes with a number of super simple ways to quickly reach our goal.