How to generate random numbers in Python

Learn to generate random numbers in Python. Explore methods, tips, real-world applications, and how to debug common errors.

How to generate random numbers in Python
Published on: 
Fri
Feb 6, 2026
Updated on: 
Tue
Feb 24, 2026
The Replit Team Logo Image
The Replit Team

Python's modules offer powerful tools to generate random numbers. This skill is key for applications in game development, cryptography, and data science, with simple and effective functions available.

You'll learn techniques to create random values, from simple integers to complex distributions. You'll also find practical tips, see real-world applications, and get advice to fix bugs in your code.

Basic random numbers with random.random()

import random
random_number = random.random()
print(random_number)--OUTPUT--0.7237845954

The random.random() function is the core of Python's random module, providing the foundation for more complex operations. It generates a single pseudo-random floating-point number with these key properties:

  • It's always greater than or equal to 0.0.
  • It's always less than 1.0.

This simple function is the building block that many other functions in the module use to generate integers, choose from sequences, or sample from various distributions. You're essentially getting the most basic unit of randomness the module offers.

Basic random number techniques

Beyond the basic float, the random module offers powerful functions for generating integers, picking from lists, and creating numbers within a specific range.

Generating integers with random.randint()

import random
random_integer = random.randint(1, 100)
print(random_integer)--OUTPUT--42

For generating random integers, you'll use the random.randint() function. It requires two arguments to define the range: a starting number and an ending number.

  • The key thing to remember is that this range is inclusive. This means the returned value can be the start number, the end number, or any integer in between.

So, random.randint(1, 100) will give you a random integer from 1 to 100, including both endpoints. It’s a straightforward way to get a whole number when you need one.

Creating random floats in a range with random.uniform()

import random
random_float = random.uniform(1.5, 8.5)
print(random_float)--OUTPUT--5.273546789

If you need a random float that isn't limited to the 0.0 to 1.0 range of random.random(), you'll want random.uniform(). This function lets you specify your own range with two arguments, a minimum and a maximum value.

  • The key difference is control—you set the boundaries for the float.
  • The resulting number will fall between your two specified points, and it's possible for the endpoints themselves to be selected.

Selecting random elements with random.choice()

import random
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
random_fruit = random.choice(fruits)
print(random_fruit)--OUTPUT--banana

When you need to select a single item from a collection, random.choice() is your go-to function. You pass it a sequence, like the fruits list, and it returns one element at random. It’s a direct and simple way to make a random selection from a group of items.

  • It works with any non-empty sequence, such as a list, tuple, or string.
  • If you try to use it on an empty sequence, your code will raise an IndexError.

Advanced random number techniques

When your needs go beyond simple random numbers, you can turn to more advanced techniques for generating arrays, controlling distributions, and ensuring reproducible results.

Generating arrays of random numbers with NumPy

import numpy as np
random_array = np.random.random(5)
print(random_array)--OUTPUT--[0.12345678 0.23456789 0.34567891 0.45678912 0.56789123]

When you need a whole set of random numbers, not just one, the NumPy library is the tool for the job. It's a powerful package for numerical computing in Python. Using np.random.random(), you can generate an entire array of random values with a single function call.

  • The integer you provide—in this case, 5—tells the function how many elements to create in the array.
  • Like the standard random.random(), it produces floats between 0.0 and 1.0, but it delivers them all at once in an efficient array structure.

Creating random numbers with specific distributions

import numpy as np
normal_distribution = np.random.normal(0, 1, 5)
print(normal_distribution)--OUTPUT--[-0.12345678  0.23456789 -1.34567891  0.45678912  1.56789123]

Sometimes, you'll need random numbers that follow a specific pattern, not just a uniform spread. NumPy's np.random.normal() function lets you generate numbers from a normal distribution, which you might know as a "bell curve." This is incredibly useful for simulating real-world data that clusters around an average.

  • The function's first argument, 0, sets the mean or the center of the distribution.
  • The second, 1, defines the standard deviation, controlling the spread of the numbers.
  • The final argument, 5, tells the function how many random values to create.

Setting seeds for reproducible random numbers

import random
import numpy as np
random.seed(42)
np.random.seed(42)
print(random.random())
print(np.random.random())--OUTPUT--0.6394267984578837
0.37454011884736133

Setting a seed with random.seed() or np.random.seed() makes your random number generation predictable. By providing a specific integer, like 42, you're giving the random number generator a fixed starting point. This means your code will produce the same sequence of "random" numbers every time it runs.

  • This is crucial for debugging or sharing your work, as it ensures anyone running your code gets the exact same results.
  • It's important to know that the standard random module and NumPy have separate random number generators. You must seed them independently if you're using both.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.

For the random number techniques we've explored, Replit Agent can turn them into production-ready tools:

  • Build a dice rolling simulator for tabletop games that uses random.randint() to generate results for different types of dice.
  • Create a data simulation dashboard that uses np.random.normal() to generate sample datasets for statistical modeling.
  • Deploy a secure password generator that uses random.choice() to create strong, unpredictable passwords.

Try it for yourself—describe your app idea to Replit Agent, and it will write the code, test it, and fix issues automatically, all in your browser.

Common errors and challenges

Generating random numbers in Python is straightforward, but a few common mistakes can lead to unexpected behavior in your code.

A frequent oversight is forgetting to set a seed with random.seed() when you need reproducible outcomes. If you don't set a seed, your script generates a new sequence of random numbers every time it runs. This can make debugging incredibly difficult, as errors may not appear consistently, and it prevents others from reliably replicating your results.

It’s also easy to get confused by the boundary rules of random.randint() and random.randrange(), leading to off-by-one errors. The key difference lies in how they handle the upper limit of the range.

  • random.randint(a, b) is inclusive, meaning the returned integer can be a, b, or any whole number in between.
  • random.randrange(start, stop) is exclusive of the upper bound, so it returns an integer from start up to, but not including, stop.

When using random.sample() to choose multiple unique items from a sequence, you might encounter a ValueError. This error occurs if you request a sample size that is larger than the population you're drawing from. You can't, for example, pull ten unique items from a list that only contains five.

Forgetting to set a seed with random.seed() for reproducible results

Forgetting to set a seed is a common pitfall when you need reproducible results for testing or debugging. Without a fixed starting point from random.seed(), the numbers generated are unpredictable, making your script's output impossible to replicate consistently.

The code below demonstrates this. Notice how running it multiple times produces a different random number with each execution, highlighting the challenge of debugging without a seed.

import random

# Different results each time the script runs
result1 = random.randint(1, 100)
# If we run the script again, we can't reproduce the same numbers
print(f"Random number: {result1}")

Since no seed is set, each run of this script produces a new, unpredictable number, making it difficult to trace issues. Now, see how a small change can make the outcome predictable.

import random

# Set seed for reproducibility
random.seed(42)
result1 = random.randint(1, 100)
# Same seed will produce the same sequence of random numbers
print(f"Reproducible random number: {result1}")

By calling random.seed(42) before generating a number, you fix the starting point for the random number generator. This ensures that random.randint(1, 100) will always return the same "random" number every time the script is executed.

This technique is essential for debugging your code or when you need to share your work and guarantee that others can reproduce your exact results. It makes your random processes predictable and testable.

Confusion between random.randint() and random.randrange() boundaries

A common source of off-by-one errors is mixing up random.randint() and random.randrange(). While they seem similar, they treat their upper boundary differently. randint() includes the endpoint, while randrange() excludes it, which can lead to unexpected results in your logic.

The code below demonstrates how this subtle difference can affect the range of numbers you generate.

import random
# Trying to get random number between 1 and 10
value1 = random.randint(1, 10)  # Includes 10
value2 = random.randrange(1, 10)  # Excludes 10
print(f"Values: {value1}, {value2}")

The code shows value1 can be 10, while value2 will always be 9 or less. This off-by-one difference is a classic trip-up. The following example clarifies how to handle this correctly to get the range you expect.

import random
# Getting random number between 1 and 10
value1 = random.randint(1, 10)  # Includes 10
value2 = random.randrange(1, 11)  # Now includes 10
print(f"Values: {value1}, {value2}")

To get the same inclusive range from both functions, you need to adjust the argument for random.randrange(). It’s a simple fix—by setting the upper limit to 11, as in random.randrange(1, 11), you ensure it can return 10. This makes its behavior match random.randint(1, 10). This adjustment prevents off-by-one errors, which are common when your logic depends on precise boundary conditions, like in loops or simulations.

Error when using random.sample() with sample size larger than population

A ValueError can pop up when using random.sample() if your requested sample size is larger than the list itself. You simply can't pick five unique items from a list that only has three. The code below demonstrates this common mistake.

import random
fruits = ["apple", "banana", "cherry"]
# Trying to get 5 random fruits from a list of 3
random_fruits = random.sample(fruits, 5)
print(random_fruits)

The code attempts to pull five items with random.sample() from the fruits list, which only holds three. This impossible request is what causes the ValueError. The following example shows the correct approach.

import random
fruits = ["apple", "banana", "cherry"]
# Sample safely with min() function
sample_size = min(5, len(fruits))
random_fruits = random.sample(fruits, sample_size)
print(random_fruits)

To prevent this error, you can use the min() function to cap the sample size at the list's actual length. By calculating sample_size = min(5, len(fruits)), you create a safeguard that ensures the number of items you request is never more than what's available. This is a crucial check when your sample size might be dynamic, such as when it's based on user input, preventing your program from crashing.

Real-world applications

Moving from theory to practice, you can use these random number skills for everything from generating secure passwords to estimating π.

Generating random passwords with random.choice()

You can create strong, unpredictable passwords by repeatedly using random.choice() to select characters from a predefined set of letters, numbers, and symbols.

import random
import string
characters = string.ascii_letters + string.digits + string.punctuation
password = ''.join(random.choice(characters) for _ in range(12))
print(password)

This snippet constructs a password by leveraging a generator expression for conciseness and efficiency. It works in a few key steps:

  • First, it defines a characters string by combining all letters, digits, and punctuation from Python's string module.
  • A generator expression, (random.choice(characters) for _ in range(12)), then produces 12 random characters from that pool.
  • Finally, the ''.join() method assembles these characters into a single string, creating the final password.

Estimating π with Monte Carlo simulation

A Monte Carlo simulation offers a clever way to estimate π by generating thousands of random points and calculating the ratio of those that fall within a designated circle.

import random
import math

points = 10000
inside_circle = sum(1 for _ in range(points) if random.random()**2 + random.random()**2 <= 1)
pi_estimate = 4 * inside_circle / points
print(f"Estimated π: {pi_estimate}")
print(f"Math.pi: {math.pi}")

This code estimates π by scattering random points and checking their position. It imagines a 1x1 square with a quarter-circle inside it. The logic hinges on a generator expression that creates thousands of random (x, y) coordinates.

  • Each point is tested with the equation x**2 + y**2 <= 1 to see if it falls inside the circle.
  • The ratio of points inside the circle to the total points approximates the ratio of the areas—which is π/4.
  • Multiplying this ratio by 4 gives you the final estimate for π.

Get started with Replit

Turn your new skills into a real tool. Tell Replit Agent to “build a secure password generator” or “create a dice rolling simulator for tabletop games.”

Replit Agent will write the code, test for errors, and deploy your app for you. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.