# 5 Best Ways to Generate Pseudo-Random Numbers in Python

💡 Problem Formulation: In many programming scenarios, one needs to generate random numbers to simulate behaviors, test algorithms, or initiate random events. In Python, this often involves generating pseudo-random numbers—which are not truly random due to being produced by an algorithm—but sufficient for most cases. This article will guide you through several methods of producing such numbers, from basic to more complex ones, with the example case of generating a random integer between 1 and 10 as our output.

## Method 1: The `random` Module

The `random` module in Python provides functionality to generate various kinds of random numbers. A commonly used function is `randint(a, b)`, which returns a random integer N such that a <= N <= b. It exploits a pseudo-random number generator like the Mersenne Twister algorithm to produce reproducible sequences of numbers that mimic randomness.

Here’s an example:

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

Output: 7

The example above uses `random.randint` to generate a single integer between 1 and 10. The output will vary each time you run the snippet due to the pseudo-random generation. It’s a simple and quick way to get random integers in the specified range.

## Method 2: The `secrets` Module

For cryptographic purposes, the `secrets` module is preferred over `random` as it’s designed to be more secure and less predictable. It contains the function `randbelow(n)` that produces a random integer from 0 to n-1. The numbers produced by this method are suitable for managing data like passwords, tokens, and other security-sensitive information.

Here’s an example:

```import secrets
print(secrets.randbelow(10) + 1)```

Output: 5

By calling `secrets.randbelow(10)` we obtain a value from 0 to 9, and by adding 1, we adjust the range to be 1 to 10. As this snippet is designed for security, it’s best used when randomness quality is of utmost importance.

## Method 3: The `numpy` Library

`numpy` is a popular library that includes functions for generating pseudo-random numbers in arrays. The function `numpy.random.randint(low, high=None, size=None)` returns random integers from the “discrete uniform” distribution of the specified dtype in the “half-open” interval [low, high).

Here’s an example:

```import numpy as np
print(np.random.randint(1, 11))```

Output: 3

This code illustrates the generation of a random integer between 1 (inclusive) and 11 (exclusive), which effectively gives us a number from 1 to 10. `numpy` is especially useful when generating large arrays of random numbers efficiently.

## Method 4: List Shuffling with `random.shuffle`

Another creative method to get a random number is to shuffle a list of numbers. Python’s `random.shuffle(x[, random])` randomly reorders the elements in a list. While this method may not be ideal for generating a single random number, it’s a great way to randomize ordered data without repetition.

Here’s an example:

```import random
numbers = list(range(1, 11))
random.shuffle(numbers)
print(numbers[0])```

Output: 8

This method first creates a list of integers from 1 to 10. Then, `random.shuffle` is used to reorder the elements in place, and the first element is taken as the random output, ensuring a unique number each time given the starting list remains constant.

## Bonus One-Liner Method 5: The `random.choice` Function

For an extremely concise method, `random.choice` lets you pick a random element from a non-empty sequence. While typically used for lists, it’s an effortless way to select a random number from a range when combined with `range()`.

Here’s an example:

```import random
print(random.choice(range(1, 11)))```

Output: 2

The one-liner uses `random.choice` to select and print a random element from the sequence created by `range(1, 11)`. Simple and intuitive, this is great when you just need a quick random number from a set list or range.

## Summary/Discussion

• Method 1: `random.randint`. Simple and flexible. Not suitable for cryptographic purposes.
• Method 2: `secrets.randbelow`. Cryptographically secure. May be overkill for non-security related tasks.
• Method 3: `numpy.random.randint`. Optimized for large datasets. Requires external library.
• Method 4: `random.shuffle`. Unique randomization of a list. Inefficient for a single number generation.
• Method 5: `random.choice`. Extremely concise. Relies on an iterable being provided.