I'd like to construct an object that works like a random number generator, but generates numbers in a specified sequence.
# a random number generator
rng = lambda : np.random.randint(2,20)//2
# a non-random number generator
def nrng():
numbers = np.arange(1,10.5,0.5)
for i in range(len(numbers)):
yield numbers[i]
for j in range(10):
print('random number', rng())
print('non-random number', nrng())
The issue with the code above that I cannot call nrng
in the last line because it is a generator. I know that the most straightforward way to rewrite the code above is to simply loop over the non-random numbers instead of defining the generator. I would prefer getting the example above to work because I am working with a large chunk of code that include a function that accepts a random number generator as an argument, and I would like to add the functionality to pass non-random number sequences without rewriting the entire code.
EDIT: I see some confusion in the comments. I am aware that python's random number generators generate pseudo-random numbers. This post is about replacing a pseudo-random-number generator by a number generator that generates numbers from a non-random, user-specified sequence (e.g., a generator that generates the number sequence 1,1,2,2,1,0,1
if I want it to).
Edit:
The cleanest way to do this would be to use a lambda to wrap your call to next(nrng)
as per great comment from @GACy20:
def nrng_gen():
yield from range(10)
nrng = nrng_gen()
nrng_func = lambda: next(nrng)
for i in range(10):
print(nrng_func())
Original answer:
If you want your object to keep state and look like a function, create a custom class with __call__
method.
eg.
class NRNG:
def __init__(self):
self.numbers = range(10)
self.state = -1
def __call__(self):
self.state += 1
return self.numbers[self.state]
nrng = NRNG()
for i in range(10):
print(nrng())
However, I wouldn't recommend this unless absolutely necessary, as it obscures the fact that your nrng keeps a state (although technically, most rngs keep their state internally).
It's best to just use a regular generator with yield
by calling next on it or to write a custom iterator (also class-based). Those will work with things like for loops and other python tools for iteration (like the excellent itertools package).