The `random`

library is a built-in Python library with many uses. We’ve covered some ways to use the library such as when creating a Dice Roll Simulator, a Password Generator, or when drawing a card in the card game War. Now that we’ve seen it in action a few times, it would be a good idea to learn more about the library in depth.

The `random`

library in Python generates numbers using the Mersenne Twister method. The Mersenne Twister is a pseudorandom number generator with deterministic results. The implementation is done in C and is threadsafe, which means it can be run in multithreaded code without fear of data contamination. Let’s take a look at the functions of the `random`

library and how we can use them.

In this post we will cover:

- Manipulating the State of the Random Library in Python
- How to Use Random Seed from the Python Random Library
- Python Random Library Random State
- Random Seed vs Random State

- Generating Random Integers in Python
- Pick a Random Integer from a Range in Python
- Pick a Random Integer with Python randint
- Pick a Random Integer of a Certain Size

- Using the Random Library on Lists in Python
- Pick a Random Choice from a Sequence
- Pick Multiple Random Choices from a Sequence
- Randomly Shuffle an Interable
- Get a Random Sample from a List with the Python Random Library

- Generating Numbers from Statistical Distributions in Python
- Code for Sampling from Statistical Distributions with the Python Random Library

# Manipulating the State of the Random Library in Python

The Mersenne Twister is a deterministic psuedorandom number generator. It produces the same results each time given the same starting state. There are two ways to manipulate the starting state of the `random`

library in Python. You can use either seed or state.

## Python Random Seed

The `random.seed()`

method takes one parameter. That parameter can be of type `None`

, `int`

, `float`

, `str`

, `bytes`

, or `bytearray`

. This is the easiest way to set the state of the random number generator object such that we can generate the same sequence of numbers every time. Let’s see how this works in action with the following Python code.

```
import random
random.seed(22)
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
```

Using a seed of 22 and generating 5 random integers from 1 to 5 should give us the same result each time. I got the list `2, 2, 1, 5, 4`

. When you run the above code, you should also get the exact same list.

## Python Random Library Random State

Setting the seed isn’t the only way to manipulate the state of the Python `random`

library. We can also manipulate it with state. There are two functions involved in this. The first function is `getstate()`

and the second function is `setstate()`

. The `getstate()`

function takes 0 parameters and the `setstate()`

function takes 1 parameter of type `tuple`

. You can’t just pass any tuple though, it has to make sense to the function, and the function expects a `tuple`

with the same structure as the one returned in `getstate()`

. Let’s generate two sets of 5 random integers from 1 to 5 with the same state. All we have to do is set `x`

to the returned value from `getstate()`

and pass it to `random.setstate()`

to set the state of the random number generator. If we set the state to `x`

twice, the two sequences should be the same.

```
import random
x = random.getstate()
random.setstate(x)
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
random.setstate(x)
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
print(x)
```

As we can see in the image below, the first 5 and the second 5 numbers are the same.

Notice we also printed out `x`

, the tuple representing the state above. Let’s take a look at what that looks like.

As you can see, that’s a lot of numbers. `x`

is a tuple of size 3 where the first entry is an `int`

, the second is a `tuple`

of length 625, and the last is `None`

. The first number represents the version number, the middle tuple represents a list of 624 seed numbers and the last one is always 624, the last number is the Gaussian Next, used to generate numbers from a Gaussian distribution (which we aren’t doing).

## Random Seed vs Random State

What’s the difference between using Random Seed and Random State for the `random`

library in Python? The `random.seed()`

function allows us to create universally reproducible results. Using `getstate()`

and `setstate()`

allows us to set the state back to where it was at the beginning of a program. Since the state is taken from the internal state of the computer, this does not guarantee universally reproducible results unless you export the state. However, it is useful for reproducing results within a program.

# Generating Random Integers in Python

Generating random integers has many useful applications such as selecting an index from a list, selecting a number to guess, or drawing the lottery. The Python `random`

library gracefully supplies us with three functions (really two, we’ll go over this) to generate random integers. These functions are `random.randrange`

, `random.randint`

, and `random.getrandbits`

. Let’s take a look at what they do and how they work.

## Pick a Random Integer from a Range

The `random.randrange()`

function takes 1 required parameter and 2 optional parameters. If only 1 parameter is passed in, the function generates a number between 0 and the passed in parameter. When two parameters are passed in, the `random.range()`

function generates a number between the two passed in numbers. If three parameters are passed in, the `random.range()`

function generates a number between the two passed in numbers in increments of the third number. All parameters are expected to be integers.

For example, if we pass in 10, we expect an output between 0 and 10 (not including 10). If we pass in 10 and 20, we expect an output between 10 and 20 (not including 20). If we pass in 10, 20, and 2, we expect an even number greater than or equal to 10 and less than 20.

```
import random
random.seed(1)
print(random.randrange(10))
print(random.randrange(10, 20))
print(random.randrange(10, 20, 2))
```

The above code (with the `random.seed()`

set to 1) should generate the numbers 2, 19, and 10 every time. Try it for yourself!

## Pick a Random Integer with Python randint

The `random.randint()`

function is actually just a wrapper around the `random.randrange()`

function. The `randint`

function takes two parameters. It returns a number between the two passed in integers. However, unlike the `randrange`

function, the `randint`

function includes the higher integer in its possible return values. You can think of it as a wrapper around `random.randrange(a, b+1)`

```
import random
random.seed(1)
print(random.randint(10, 20))
```

With a seed of 1, the above code should always return 10.

## Pick a Random Integer of a Certain Size with Python

The `random.getrandbits`

function takes one parameter, the number of bits. It returns a number represented by the number of bits. In other words, it returns a number between 0 and 2 to the `x`

where `x`

is the parameter. For example, if we call `random.getrandbits(9)`

we expect a number between 0 and 512.

```
import random
random.seed(1)
print(random.getrandbits(9))
```

With a random seed of 1, `random.getrandbits(9)`

should return 60 every time.

# Using the Random Library on Lists in Python

So far we’ve seen how to manipulate the state of the random object and generate random integers in Python. Now let’s take a look at how we can use the random number on iterables in Python. I specifically put lists in the section title, but we can use these on any iterable in Python including strings, lists, tuples, sets, byte sequences, and ranges.

Before we play around with the different functions for manipulating a sequence in Python, let’s establish a sequence to use. To do this, we set a random seed and then generate a sequence of 10 numbers from 1 to 100 using list comprehension.

```
import random
random.seed(69)
seq = [random.randint(1, 100) for _ in range(10)]
print(seq)
```

This will generate the list [88, 5, 13, 22, 9, 78, 45, 42, 71, 54]. Now let’s look at the four functions for sequences in the Python `random`

library: `random.choice`

, `random.choices`

, `random.shuffle`

, and `random.sample`

.

## Pick a Random Choice from a Sequence

The `random.choice`

function is the simplest one. It takes one parameter, a non-empty sequence and will raise an error if the sequence is empty. The function returns a random entry from that sequence. Running `random.choice`

on the sequence above should return 42.

```
import random
random.seed(69)
seq = [random.randint(1, 100) for _ in range(10)]
print(seq)
print(random.choice(seq))
```

## Pick Multiple Random Choices from a Sequence

This one has an interesting parameter set up. There is one mandatory parameter, the sequence, and three optional parameters, but two of those optional parameters should not be used together. The three optional parameters are `weights`

, `cum_weights`

, and `k`

. The `weights`

and `cum_weights`

parameters default to `None`

meaning each option is weighted the same, and `k`

, the number of choices returned, defaults to 1.

The reason that `weights`

and `cum_weights`

shouldn’t be used together is because they represent the same thing – the weighted probability that a number in the sequence will be picked. The weights list should be the same length as the sequence. If `weights`

is passed in, it will be turned into `cum_weights`

, so passing in `cum_weights`

saves us a bit of processing time when calling `random.choices`

. The list of weights indicates the “weight” or probability of picking a number. For example, a weight list of [1, 1, 1] will have a cumulative weight list of [1, 2, 3].

```
import random
random.seed(69)
seq = [random.randint(1, 100) for _ in range(10)]
print(seq)
weights = [random.randint(1, 10) for _ in range(10)]
print(weights)
cum_weights = [sum(weights[:i+1]) for i in range(10)]
print(cum_weights)
random.seed(1)
print(random.choices(seq, weights=weights, k=5))
random.seed(1)
print(random.choices(seq, cum_weights=cum_weights, k=5))
print(random.choices(seq, k=5))
print(random.choices(seq))
```

The above code should result in the output below. Note that setting `random.seed`

before each of the `random.choices`

calls with the `weights`

and `cum_weights`

derived from the `weights`

variable results in the same output. Notice that we can also call `random.choices`

with no weights function. If we call it with no `k`

input, it defaults to returning 1 choice. Notice that unlike `random.choice`

, `random.choices`

returns a list.

## Randomly Shuffle an Interable

Choosing random entries from an iterable isn’t the only thing we can do with the `random`

library. We can also use it to shuffle up our entries like we did in War, Blackjack, and Texas HoldEm. Starting with the same sequence we’ve been using this whole time, we can see how `random.shuffle`

works. It takes one parameter, the sequence, and shuffles it up. We can actually pass an optional argument that returns a random float, but this is almost always just the `random()`

function.

It’s important to note that `random.shuffle()`

is an *in-place* shuffle function. It does not return anything. It simply changes the passed in sequence.

```
import random
random.seed(69)
seq = [random.randint(1, 100) for _ in range(10)]
print(seq)
random.shuffle(seq)
print(seq)
```

When we run the above code, we should see an output exactly like the one below.

## Get a Random Sample from a List with the Python Random Library

Finally, we can also use the `random`

library to return a sample from a list. What’s the difference between a random sample and random choices? A random sample is non-replacing. Notice that in our `random.choices`

example, the list had a repeat in it, `random.sample`

will not return repeats *unless there are repeats in the sequence itself*.

The `random.sample()`

function takes 3 parameters, 2 mandatory and 1 optional. The two mandatory parameters are the sequence and the number of entries we’d like sampled. The optional parameter is a `count`

parameter that tells the sampling function how many times each entry in the original sequence can be sampled.

```
import random
random.seed(69)
seq = [random.randint(1, 100) for _ in range(10)]
print(seq)
print(random.sample(seq, 5))
seq2 = [2, 3, 4]
random.seed(10)
print(random.sample(seq2, 5, counts=[2, 3, 4]))
seq3 = [2, 2, 3, 3, 3, 4, 4, 4, 4]
random.seed(10)
print(random.sample(seq3, 5))
```

In the example we will see that sampling from a sequence of [2, 3, 4] with a count equal to [2, 3, 4] is equivalent to sampling from a sequence of [2, 2, 3, 3, 3, 4, 4, 4, 4]. The above code should result in the below output every time. Notice that we have to set the random seed before we do the sample to ensure that it’s the same sample.

# Generating Numbers from Statistical Distributions in Python

There are 12 built-in statistical distributions that are available to generate from in the random library.

- The default random distribution, which generates a floating-point number between 0 and 1.
- The uniform random distribution, which takes two parameters,
`a`

and`b`

. It generates a random number between`a`

and`b`

. - The triangular distribution, which takes three parameters,
`a`

,`b`

, and`c`

. It generates a number in the triangular distribution with base from`a`

to`b`

with a peak at`c`

. - The beta distribution, which takes two parameters,
`alpha`

, and`beta`

. Generates a number between 0 and 1 from the beta distribution with parameters`alpha`

and`beta`

. - The exponential distribution, which takes one parameter,
`lambd`

. Generates a number from the exponential distribution with mean 1/`lambd`

. - The Gamma distribution, which takes two positive valued parameters,
`alpha`

, and`beta`

. Generates a number from the probability density function of Gamma with shape parameter`alpha`

and scale parameter`beta`

. - The Gaussian distribution, which is the normal distribution with a faster, but not threadsafe, implementation. The
`random.gauss()`

function takes two parameters,`mu`

and`sigma`

. It returns a number from the normal distribution with mean`mu`

and standard deviation`sigma`

. - The Log Normal distribution, which takes two parameters,
`mu`

and`sigma`

. It generates a number from the log normal distribution for a normal distribution with mean`mu`

and standard deviation`sigma`

. - The Normal distribution, which takes two parameters,
`mu`

and`sigma`

. It generates a number from the normal distribution with mean`mu`

and standard deviation`sigma`

. - Von Mises’ distribution, which takes two parameters,
`mu`

and`kappa`

. Von Mises’ distribution is the normal distribution for angles. Generates a value between 0 and 2pi with mean`mu`

and concentration`kappa`

. When`kappa`

is set to 0, this becomes a uniform distribution. - The Pareto distribution, which takes one parameter,
`alpha`

. It generates a number from the pareto distribution with shape`alpha`

. For reference the famous 80-20 Pareto distribution comes from an alpha of 1.16. - The Weibull distribution, which takes two parameters,
`alpha`

and`beta`

. It generates a number from the Weibull distribution with scale`alpha`

, and shape`beta`

.

## Code for Sampling from Statistical Distributions with the Python Random Library

The code below shows how we can sample numbers from each of the distributions above:

```
import random
print(f"Sample from basic random distribution from 0 to 1: {random.random()}")
print(f"Uniform Random Sample from 2 to 4: {random.uniform(2, 4)}")
print(f"Triangle Random Sample from 1 to 10 with a mode of 8: {random.triangular(1, 10, 8)}") #defaults to 0, 1, 0.5
print(f"Sample from the Beta distribution alpha=1, beta=2: {random.betavariate(1, 2)}") #a, b > 0
print(f"Sample from exponential distribution with a mean of 1/9: {random.expovariate(9)}") #parameter != 0
print(f"Sample from Gamma distribution with alpha=1, beta=2: {random.gammavariate(1, 2)}") #a, b > 0
print(f"Sample from Gaussian (Normal) with mean 1 and standard deviation 0.1: {random.gauss(1, 0.1)}") #not-thread-safe but faster version of normalvariate
print(f"Sample from Log Normal Distribution with mean 1 and standard deviaiton 0.1: {random.lognormvariate(1, 0.1)}") #the exponential of the normal around a, b
print(f"Sample from Normal Distribution with mean 1 and standard deviation 0.1: {random.normalvariate(1, 0.1)}") #normal distribution
print(f"Sample from von Mises/circular Normal Distribution with mean ~pi, concentration 0.1: {random.vonmisesvariate(3.14, 0.1)}") #a, b are angle and concentration, b=0 gives uniform random angle
print(f"Sample from Pareto distribution with shape 1: {random.paretovariate(1)}") #a is the shape parameter
print(f"Sample from Weibull distribution with scale 2 and shape 3: {random.weibullvariate(2, 3)}") #a is the scale, b is the shape
```

## Summary of How to Use the Python Random Library

We looked at four big parts of the Python `random`

library in this post. First we looked at manipulating the “state” of the `random`

library. We can manipulate that via random seed and random state.

Next we looked at how to generate random integers. There are three main ways that the Python random library allows us to generate integers. We can use the `randint`

function, generate a random integer from a range, or generate a random integer of a certain bytesize.

After generating random integers, we looked at working with lists. We looked at how to pick a single random choice and picking multiple random choices from a sequence. Then we looked at how to randomly shuffle an iterable. The last list operation we looked at with the Python random library is how to get a random sample from a list.

The last thing we looked at from the random library was generating numbers from statistical distributions. We also covered the 12 statistical distributions that are included.

## Further Reading

- The Best Named Entity Recognition (NER) in Python
- Build Your Own AI Text Summarizer in Python
- Build an AI Content Moderation System
- NLP Stop Words with spaCy and NLTK
- Create a High Level Design Document

I run this site to help you and others like you find cool projects and practice software skills. If this is helpful for you and you enjoy your ad free site, please help fund this site by donating below! If you can’t donate right now, please think of us next time.

## One thought on “A Comprehensive Guide to the Python Random Library”