When I don't want an upper bound I'll often use sys.maxint for the upper bound as an approximation

Answer from Eric Renouf on Stack Overflow
🌐
Python documentation
docs.python.org › 3 › library › random.html
random — Generate pseudo-random numbers
February 23, 2026 - The default random() returns multiples of 2⁻⁵³ in the range 0.0 ≤ x < 1.0. All such numbers are evenly spaced and are exactly representable as Python floats. However, many other representable floats in that interval are not possible selections. For example, 0.05954861408025609 isn’t an integer multiple of 2⁻⁵³.
Discussions

Can Python generate a random number that excludes a set of numbers, without using recursion? - Stack Overflow
I'm sure that there's a nice, Pythonic, non-recursive way to do it. ... Generate one random number and map it onto your desired ranges of numbers. If you wanted to generate an integer between 1-4 or 7-10, excluding 5 and 6, you might: More on stackoverflow.com
🌐 stackoverflow.com
Whats your preferred way of generating a random number, e.g. between 1 and 100 ?
random.randint(0, 100) More on reddit.com
🌐 r/learnpython
41
6
January 25, 2022
Generate random number without range for a given argument for the same length in python be it in numeric or alphanumeric - Stack Overflow
Generate random number without range for a given parameter for the same length in python be it in numeric or alphanumeric ... I pass a numeric value (123456) to my function, then the function should return a random integer number say 876529 for the same length and the characters in the value ... More on stackoverflow.com
🌐 stackoverflow.com
April 3, 2020
randomness - pick K random integers without repetition - Computer Science Stack Exchange
Suppose we've to pick $K (\le N)$ random integers in the range $[0, N - 1]$ for very large $N$ such that there is no repetition, while also deterministically minimizing the number of calls made to ... More on cs.stackexchange.com
🌐 cs.stackexchange.com
January 23, 2024
🌐
Note.nkmk.me
note.nkmk.me › home › python
Generate Random Numbers (int and float) in Python | note.nkmk.me
August 16, 2023 - If you want to make a list of random integers without duplicates, you can use random.sample() to select elements from a range(). print(random.sample(range(10), k=5)) # [6, 4, 3, 7, 5] print(random.sample(range(100, 200, 10), k=5)) # [130, 190, ...
🌐
DigitalOcean
digitalocean.com › community › tutorials › randint-method-in-python
The randint() Method in Python | DigitalOcean
August 4, 2022 - It works in the same way randrange(beg,end) does, and hence is an alias for the same. Let us look at the given code below, it illustrates the use and working of the randint() method. import random beg=10 end=100 random_integer = random.randint(beg, end) print("The random integer is :", ...
🌐
GeeksforGeeks
geeksforgeeks.org › python-generate-random-numbers-within-a-given-range-and-store-in-a-list
Generate random numbers within a given range and store in a list - Python - GeeksforGeeks
May 5, 2025 - For example, you might want to generate 5 random numbers between 20 and 40 and store them in a list, which could look like this: [30, 34, 31, 36, 30]. Let's explore different methods to do this efficiently. random.choices() function is an efficient ...
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-randint-function
randint() Function in Python - GeeksforGeeks
March 20, 2026 - Example 1: This example generates a random number between -5 and -1. It demonstrates that randint() also works with negative integers. ... Explanation: random.randint(-5, -1) returns a random integer from -5 to -1, including both endpoints.
Find elsewhere
🌐
Enki
enki.com › post › get-random-number-in-python
Enki | Blog - How to generate random numbers in Python
Learn how to generate random numbers in Python using the random module in this comprehensive guide from Enki, covering basic to advanced techniques for probabilistic algorithms, test data generation, game development, and real-world simulation tasks.
🌐
MachineLearningMastery
machinelearningmastery.com › home › blog › how to generate random numbers in python
How to Generate Random Numbers in Python - MachineLearningMastery.com
September 18, 2023 - These little programs are often a function that you can call that will return a random number. Called again, they will return a new random number. Wrapper functions are often also available and allow you to get your randomness as an integer, floating point, within a specific distribution, within a specific range, and so on.
🌐
W3Schools
w3schools.com › python › ref_random_randint.asp
Python Random randint() Method
Built-in Modules Random Module ... Python Study Plan Python Interview Q&A Python Bootcamp Python Training ... The randint() method returns an integer number selected element from the specified range......
Top answer
1 of 3
1
  1. For strings: Random shuffle of letters A-Z and number 0-9 and returns length of input seed
  2. For numbers: Shuffles digits 0-9 and converts to a number to return
  3. Shuffling is based upon the input (either string or number)

Code

import random
import string

def rand_gen(seed):
  " Generate random strings and numbers based upon seed "

  # Seed random number generator for shuffling
  random.seed(seed)

  # Alphabet based upon type of input (string or integer)
  if isinstance(seed, int):
    # Result based upon numbers 0-9
    alphabet = string.digits
    seed = str(seed)
    is_int = True
  else:
    # Result uses letters in upon A-Z and 0-9
    alphabet = string.ascii_uppercase + string.digits
    is_int = False

  # Output based upon random shuffling of alphabet
  x = list(alphabet)
  while True:
    random.shuffle(x)
    if x[0] != '0' or not is_digit:  # Avoid left most digit being 0 for when working with numbers
      break 

  output = ''.join(x[:len(seed)])
  if is_int:
    return int(output)
  else:
    return output

Test

for i in range(1, 15):
  print(f'Numeric Seed: {i:<12} \tString: {rand_gen(i)}')

for i in range(1, 10):
  seed = 'a'*i
  print(f'Charact Seed: {seed:<12} String: {rand_gen(seed)}')

Output

Output width same as input seed

Numeric Seed: 1             String: 6
Numeric Seed: 2             String: 5
Numeric Seed: 3             String: 1
Numeric Seed: 4             String: 8
Numeric Seed: 5             String: 2
Numeric Seed: 6             String: 5
Numeric Seed: 7             String: 8
Numeric Seed: 8             String: 8
Numeric Seed: 9             String: 9
Numeric Seed: 10            String: 52
Numeric Seed: 11            String: 26
Numeric Seed: 12            String: 89
Numeric Seed: 13            String: 30
Numeric Seed: 14            String: 90
Charact Seed: a            String: Q
Charact Seed: aa           String: ZX
Charact Seed: aaa          String: 5DE
Charact Seed: aaaa         String: 3AV7
Charact Seed: aaaaa        String: I2J76
Charact Seed: aaaaaa       String: ZRHENX
Charact Seed: aaaaaaa      String: R17ZXV4
Charact Seed: aaaaaaaa     String: QEGZYTNA
Charact Seed: aaaaaaaaa    String: VDIFQO7SH
2 of 3
1

by doing some research I will come with this ugly solution :

First you will generate a list with all ascii character:

value = '1230LE'
t = list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')

Then remove from this long string the value character present in your string value (using t.index to find the index of the character):

for c in value:
   del t[t.index(c)]
# Output (without '1', '2', '3', '0', 'L', 'E')
# ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','F','G','H','I','J','K','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','4','5','6','7','8','9']

Then you only need to do a basic generator based on your new string:

from random import choice
n = len(value)
str_characters = ''.join(t) # 'abcdefghijklmnopqrstuvwxyzABCDFGHIJKMNOPQRSTUVWXYZ456789'
generated_value = [choice(str_characters) for i in range(n)] # ['7', 'l', 'N', 'j', 'c', 'i']
''.join(generated_value) #'7lNjci'

Here you are, it's a tricky solution but it's working.

If you want to do it for only numeric you can use this value for t:

t = list('0123456789')

Full code :

value = '1230LE'
t = list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
for c in value:
   del t[t.index(c)]
from random import choice
n = len(value)
str_characters = ''.join(t) # 'abcdefghijklmnopqrstuvwxyzABCDFGHIJKMNOPQRSTUVWXYZ456789'
generated_value = [choice(str_characters) for i in range(n)] # ['7', 'l', 'N', 'j', 'c', 'i']
''.join(generated_value) #'7lNjci'

Hope it will help, have fun !

Top answer
1 of 6
16

Ṃųỻịgǻňạcểơửṩ mentioned that this is the reservoir problem. The reservoir sampling problem, though, is explicitly a very strict requirement for a streaming algorithm, i.e. it works in just one pass over a stream of values whose eventual size we don't know.

In this case, we want to do it in one pass, but we do know both N and K, so the problem is a little different and it permits a simpler solution.

Floyd's algorithm is designed for this task. It has some resemblance to both the Fisher-Yates shuffle and to reservoir sampling.

A couple of minor differences from the framing in your question:

  • K < N
  • we use randint(i, j) which produces a random integer between i and j inclusive
  • the samples will be generated in the range 1 to N inclusive (but of course it is easy to adjust this at the end)

Here's the Python code:

import random

n = 200
k = 5
s = set()

for j in range(n-k+1, n+1):
    t = random.randint(1, j)
    if t not in s:
        s.add(t)
    else:
        s.add(j)
        
print(s)

A good source for the origin of and mathematical justification for Floyd's algorithm is this article by Jon Bentley from 1987. It's worth noting that the algorithm only calls randint() K times.

A very brief description of how it works is that, on iteration t, it draws a number randomly from [1..n-k+t]. If the number has not been drawn before, it is added to the sample. Otherwise, it adds the number n-k+t to the sample. This works to give the proper probabilities of inclusion in the final set.

In Bentley's article there is a description of the recursive formulation of the algorithm:

We can appreciate the correctness of Floyd’s algorithm anecdotally. When M = 5 and N = 10, the algorithm first recursively computes in S a 4-element random sample from 1..9. Next it assigns to T a random integer in the range 1..10. Of the 10 values that T can assume, exactly 5 result in inserting 10 into S: the four values already in S, and the value 10 itself. Thus element 10 is inserted into the set with the correct probability of 5/10.

I can't do better than that explanation, right now!

The algorithm has been mentioned on StackOverflow and proofs are here on Math SE.

2 of 6
6

What quality of randomness do you need? You can construct a Linear Congruential Generator as a PRNG with period of N (or the next prime above N) and discard out-of-range samples.

Use rand() only to seed your LCG PRNG.

Of course you get the same sequence every time, just from different start points, unless you also try to randomize your LCG's multiplier and adder parameters. Or as John Bollinger puts it, for any given K it can produce only about N distinct K-element samples.

Re-randomizing the multiplier (a) and adder (c) constants while still satisfying the conditions for period m (the modulus) can make multiples sets of sequences possible. And/or raise m so there are more numbers between N and m you'd have to discard if generated. But there's limited freedom so this only goes so far. (And depending on LCG parameters there can be significant correlation between numbers.)

This requires O(1) storage and negligible time per result, just a 64-bit multiply, add, and modulo.
If you need bigints for this, I guess O(log2(N)) storage and time per query with a small constant factor. But 10^18 < 2^64. Initial setup time requires finding a prime above N.


Quality of randomness is low: even the best LCGs are not great pseudo-random generators by modern standards, although some of their downsides come from choices like a power-of-2 modulus which makes the low-order bits highly correlated. (Other downsides include a short period, which we're taking advantage of here.) But automated selection of LCG parameters to fit a given period can result in generators much worse than a "good" LCG. For some small N, pairs of consecutive numbers are common in the output sequence. Maybe different LCG parameters with the same or similar period could avoid that.

I used this in practice for a partly-finished subtree-pruning-regrafting library that I never did much with, GPLed code on Github with comments explaining the algorithm, citing Knuth TAOCP for the conditions that produce period m, and Numerical Recipes for some PRNG quality folklore and best practices. The LCG-selection part does work correctly, but basically gives up and makes the multiplier 1 and adder 0 in some corner cases. Also for tiny maxval = N, 6 or less, since for this library's purposes, 6 was few enough to just brute-force try all possibilities and see which tree gave the maximum likelihood.

struct lcg {
    unsigned int state;
    unsigned int a, c, m;
    unsigned int startstate;
};

/******************** Linear Congruential Generator setup ************/
/* to generate all possible SPRs in a pseudo-random order, we generate
 * all the numbers between 0 and the number of possible SPRs once each
 * without repetition using an LCG of the form: x_n+1 = x_n*a + c mod m.
 */
/*
 * Knuth: TAOCP 3.2.1: ex 2: if a and m are relatively prime,
 * the number X_0 will always appear in the period.  (will return to start?)
 *
 *  3.2.1.2: Theorem A: An LCG will have period m iff:
 *   -  c is relatively prime to m
 *   -  b = a-1 is a multiple of p, for every prime p dividing m
 *   -  b is a multiple of 4, if m is a multiple of 4
 *
 *  3.2.1.3: ex 4:  m = 2**e >= 8  ->  maximum potency when a mod 8 = 5.
 *   small multipliers are to be avoided.
 *
 * Numerical recipies suggests c = a prime close to (1/2 - sqrt(3)/6)*m
 */

/* make up some parameters for an LCG that will have the maximum period
 * equal to the range, so every value is generated once.
 * When maxval doesn't have any repeated prime factors, a = m+1,
 * which is the same as a=1.  It's not exactly random, but it does still
 * mix up which SPRs are done.
 *
 * TODO: take advantage of the fact that maxval = floor(sqrt(maxval))*ceil(sqrt(maxval))
 *  could do that, but then the code would be less general-purpose
 * successfully brute-force tested for maxval=1..1000.
 */
void findlcg(struct lcg *lcg_params, int maxval)
{
    unsigned int a, b, c, m = maxval;
    int i;

    primesetup (maxval+maxval/2);

    if (m<=6){ // will be either 6 or 2.  Just loop in order
        b=0;
        c=1;
    }else{
        int divlimit = m;
        b=1; // b must be a multiple of all of m's prime factors
        if (!(m%2)){
            b=2;
            while (divlimit%2 == 0) divlimit /= 2;
        }
        for (i=3 ; i <= divlimit ; i+=2){
            if (is_prime(i) && m%i == 0){
                b *= i;
                while (divlimit%i == 0) divlimit /= i;
            }
        }

        if (!(m%4)){    // if m is a mult of 4, b must be.
            while (b%4) b *= 2;
        }

        /* make sure a isn't too small */
        while (b<sqrtf(m)) b*=7;

        if (b == m) b=0;  // just give up and avoid overflow

// Numerical Recipies says there is "lore" behind this... :)
// TAOCP says it's useless unless the multiplier sucks (section 3.3.3, eq. 40)
// That would be us.
        c = next_prime(max(5, (0.5 - sqrtf(3)/6.0)*m - 2));
        while (m%c == 0) c = next_prime(c+1);
        // Luckily we don't have to test for c>m, because it doesn't
        // happen with any m<100, and there are enough primes later...
/* I've observed that when a == m, (e.g. a=13, c=13, m=72) you often get
 * two consecutive numbers...  Do something to avoid that if it's a problem */
    }

    a = b+1;

    unsigned long long l = (unsigned long long)a * m;
    if (l > ULONG_MAX){
        fprintf(stderr, "spr: chosen Linear Congruential Generator is bogus\n"
        "   x_n+1 = x_n*%u+%u mod %u\n"
        "   a*m > ULONG_MAX, so it would overflow :(\n", a, c, m);
    }

    lcg_params->a = a;
    lcg_params->c = c;
    lcg_params->m = m;
    lcg_params->startstate = UINT_MAX;
    lcg_params->state = rand() % m;
}

My use-case was smallish trees so for prime finding I just used a straightforward Sieve to find true primes, not just relatively-prime which would be sufficient. Quality of pseudo-randomness was not a priority at the time, before moving on to other work. There might be room to spend more time choosing LCG parameters better than the algorithm shown here.

🌐
Shiksha
shiksha.com › home › it & software › it & software articles › programming articles › how to generate random numbers in python?
How to Generate Random Numbers in Python? - Shiksha Online
September 6, 2024 - Import the random module of Python. Take an integer input from the user as the seed value and store it in the variable val. Then, call the seed() function with the input seed value as the argument.
🌐
SciPy
docs.scipy.org › doc › numpy-1.15.1 › reference › generated › numpy.random.randint.html
numpy.random.randint — NumPy v1.15 Manual
August 23, 2018 - similar to randint, only for the closed interval [low, high], and 1 is the lowest value if high is omitted. In particular, this other one is the one to use to generate uniformly distributed discrete non-integers. ... >>> np.random.randint(2, size=10) array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0]) >>> ...
🌐
The New Stack
thenewstack.io › home › how to generate a random number in python
How to Generate a Random Number in Python - The New Stack
November 7, 2024 - python3 simplerand.py Every time you run the program, you should see a pseudo-random number between 0 and 10. If you wanted to not include the outer ranges of our limit, you’d use the randrange() function. By using this function, you’d exclude ...
🌐
Python
docs.python.org › 3.1 › library › random.html
9.6. random — Generate pseudo-random numbers — Python v3.1.5 documentation
Return a randomly selected element from range(start, stop, step). This is equivalent to choice(range(start, stop, step)), but doesn’t actually build a range object. ... Return a random integer N such that a <= N <= b.
🌐
Sentry
sentry.io › sentry answers › python › generate random integers within a range in python
Generate random integers within a range in Python | Sentry
May 15, 2023 - As noted in a warning near the top of the random module’s documentation, values produced by its generators should not be used for security purposes. For that, we’ll need the secrets module, which provides a randbelow method we can use to generate a random integer between 0 and the provided argument, exclusive.