The random module in the standard library provides a fast and powerful pseudorandom number generator. By pseudorandom, we mean that the numbers generated are not truly random. But that shouldn't be an issue as they are still "random enough" for most practical purposes. 

Generating random numbers

The random() function in the module returns a random floating point number which falls in the range 0.0 <= n < 1.0.  

random()

The function takes no argument.

#import the random module
import random

#use the random function
print(random.random())

We can scale up the value returned by the function by multiplying it by a larger number. For example, to get a number between 0 and 10, we can simply multiply the value with 10.

#import the random module
import random

#use the random function
value = random.random()

#get an integer between 0 and 10
print(int(value * 10))

#get an integer betwen 0 an 50
print(int(value * 50))

The uniform() function

Unlike the random() function,  the uniform() function takes in arguments to define the range between which the random numbers will be generated.

uniform(a, b)
a The lower range limit.
b The upper range limit

The function returns a random number that falls in the range [a, b)

#import the random module
import random

#Use the uniform function
print(random.uniform(50, 100))
print(random.uniform(200, 300))

The following example uses the uniform() function to get 5 random numbers between 0 and 100.

import random

nums = []

for i in range(5):
    nums.append(random.uniform(0, 100))

print(nums)

Random integers

We have previously seen how we can generate integer values by scaling up(or down) a random values generated by random() or uniform() functions. The random module also provides a native and more convenient function for exactly this purpose, the randint() function.

randint(a, b)

The function returns a random integer value  between a to b, with both a and b included.

Use the randint() function to generate random integers in a given range.

import random

print(random.randint(0, 1000))
print(random.randint(0, 1000))
print(random.randint(0, 1000))
print(random.randint(0, 1000))
print(random.randint(0, 1000))

Picking random items from a sequence

One of the common uses of random number generators is to select a random element from a sequence. While this can be achieved through the various functions we have covered above, the module offers us a more convenience function for achieving the same. The choice() function picks a random element from a given non-empty sequence.

choice(seq)

Picking a random item from a sequence

import random

L = ["Python", "C++", "Java", "Ruby", "Kotlin", "PHP", "Swift"]

#pick a random item
print(random.choice(L))

#pick another
print(random.choice(L))

Shuffling a list

The shuffle() function allows us to randomly reorganize list elements. The function does the shuffling in place, meaning that the list provided as an argument gets modified. This also makes it impossible to use the function with data types that  do not support item assignment, such as tuples.

shuffle(L)

Shuffling a list

import random 

L = ["Python", "C++", "Java", "Ruby", "Kotlin", "PHP", "Swift"]

#Shuffle list L
random.shuffle(L)

print(L)

Sampling

Sampling refers to  the process of selecting a subset of data from a larger set in order represent the larger set as whole. 

The  random.sample() function selects a specified number of items from a sequence (e.g. a list, tuple, or string). It returns a list of randomly selected items from the given sequence, without modifying the original sequence. 

sample(seq, k, *args, counts = None)

using the sample function

import random 

# Define a list of items to sample 
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

# Sample 4 items from the list 
random_sample = random.sample(items, 4) 

# Print the sampled items 
print(random_sample)

Seeding

Whenever the random() function is called, it returns a  unique number, it is almost always impossible to get that number any other time. While this is a useful feature,  in some cases we may need to reproduce the numbers once they are generated. For example this can be especially useful for experimenting, testing and debugging purposes, among many other use cases.

Seeding refers to the process of setting a value, known as a seed,  for the pseudorandom number generator so that  the sequence of numbers produced by the generator is reproducible. When we do this, the generator saves the numbers associated with a particular seed so that  whenever the same seed is used the sequence of numbers produced will be the same.

We use the seed() function in the module to set a seed value.

seed(a = None, version = 2)

Using random.seed() to generate the same sequence of random numbers. 

import random

## Initializing the seed 
random.seed(1) 

# Generating four random numbers 
print(random.randint(0, 100)) 
print(random.randint(0, 100))
print(random.randint(0, 100)) 
print(random.randint(0, 100)) 

#Re-intialize the seed
random.seed(1)
print("\nReinitialized the seed\n") 

# Generating the same random numbers
print(random.randint(0, 100)) 
print(random.randint(0, 100))
print(random.randint(0, 100)) 
print(random.randint(0, 100)) 

The value used as seed can only be of any of the following types  None, int, float, str, bytes, or bytearray.

Saving states

The internal state of the pseudorandom generator can be saved in the hard disk in order to control the numbers generated in the subsequence runs. This ensures that the generator is aware of its previous state thus reducing the likelihood of repeated values.  We achieve this primarily using two functions, the  getstate() and the setstate().

The following example shows a template of how this can be achieved.

import random
import os
import pickle

if os.path.exists("state.dat"):
     # Restore the previously saved state
     with open("state.dat", "rb") as f:
          state = pickle.load(f)
          random.setstate(state)
else:
    #set a seed value
    random.seed("my_seed")

#-------------------
#Use the random generator to produce random values
#-------------

#save the state
with open("state.dat", "wb") as f:
    pickle.dump(random.getstate(), f)

#Continue using the generator.