如何制作一个具有随机数生成器之类的接口的对象,但实际上会生成指定的序列?

Ali*_*rze 18 python generator python-3.x

我想构造一个像随机数生成器一样工作的对象,但以指定的顺序生成数字。

# 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())
Run Code Online (Sandbox Code Playgroud)

上面代码的问题是我无法nrng在最后一行调用,因为它是一个生成器。我知道重写上面代码的最直接方法是简单地循环非随机数而不是定义生成器。我更喜欢让上面的示例工作,因为我正在处理大量代码,其中包含一个接受随机数生成器作为参数的函数,并且我想添加传递非随机数字序列而不重写的功能整个代码。

编辑:我在评论中看到一些混乱。我知道 python 的随机数生成器生成伪随机数。这篇文章是关于用一个数字生成器替换伪随机数生成器,该数字生成器从非随机的、用户指定的1,1,2,2,1,0,1序列生成数字(例如,如果我想要的话,可以生成数字序列的生成器)。

Gre*_*Guy 20

您可以next()使用生成器或迭代器作为参数进行调用,以从中提取一个元素。预先将生成器保存到变量中可以让您多次执行此操作。

# make it a generator
def _rng():
    while True:
        yield 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]

rng = _rng()
nrng = _nrng()
for j in range(10):
    print('random number', next(rng))
    print('non-random number', next(nrng))
Run Code Online (Sandbox Code Playgroud)

  • @PranavHosangadi 他们可以使用“lambda: next(nrng)”作为参数,而不是传递“nrng”... (7认同)
  • 这是一个很好的(并且受到好评的)观点。但是,您可以使用“def _nrng(): return iter(np.arange(1, 10.5, 0.5))”(甚至“_nrng = lambda:np.arange(1, 10.5, 0.5)”以更少的开销实现相同的效果。 `)。 (2认同)

Mar*_*cin 16

编辑:

最简洁的方法是使用 lambda 将您的调用包装到next(nrng)@GACy20 的精彩评论中:

def nrng_gen():
    yield from range(10)

nrng = nrng_gen()

nrng_func = lambda: next(nrng)

for i in range(10):
    print(nrng_func())
Run Code Online (Sandbox Code Playgroud)

原答案:

如果您希望对象保持状态并看起来像函数,请使用__call__方法创建自定义类。

例如。

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())
Run Code Online (Sandbox Code Playgroud)

然而,除非绝对必要,否则我不会推荐这样做,因为它掩盖了你的 nrng 保持状态的事实(尽管从技术上讲,大多数 rng 在内部保持其状态)。

最好通过yield调用 next 来使用常规生成器或编写自定义迭代器(也是基于类的)。这些将与 for 循环和其他用于迭代的 python 工具(如优秀的 itertools 包)一起使用。


Pra*_*adi 7

np.random.randint可以记住它生成的最后一个数字,因为它是该类的函数np.random.RandomState。Numpy 只是为类方法添加别名,以便可以直接从np.random模块访问它,而不是通过类访问它。

知道了这一点,您可以编写自己的类来工作,如下所示:

class NotRandom:

    numbers = np.arange(1,10.5,0.5)
    last_index = -1

    @classmethod
    def nrng(cls):
        cls.last_index += 1
        if cls.last_index < len(cls.numbers):
            return cls.numbers[cls.last_index]
        # else:
        return None

# Create an alias to the classmethod
nrng = NotRandom.nrng      # Note this is OUTSIDE the class
Run Code Online (Sandbox Code Playgroud)

然后,你可以这样做:

print(nrng())    # 1.0
print(nrng())    # 1.5
print(nrng())    # 2.0
Run Code Online (Sandbox Code Playgroud)

如果您希望能够有多个并发实例nrng,您可以创建nrng()一个实例方法而不是类方法:

class NotRandom:
    def __init__(self):
        self.numbers = np.arange(1,10.5,0.5)
        self.last_index = -1

    def nrng(self):
        self.last_index += 1
        if self.last_index < len(self.numbers):
            return self.numbers[self.last_index]
        # else:
        return None

# Create an object. Then create an alias to its method
nrng = NotRandom().nrng 
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用nrng()引用绑定到您创建的实例的方法NotRandom。如果你想要另一个实例,你也可以拥有:

another_notrandom = NotRandom()
nrng2 = another_notrandom.rng

print(nrng())    # 1.0
print(nrng())    # 1.5

print(nrng2())   # 1.0

print(nrng())    # 2.0

print(nrng2())   # 1.5

Run Code Online (Sandbox Code Playgroud)

  • @user253751 [全局变量并不是一个好主意。](//stackoverflow.com/q/19158339/843953) 该类很好地封装了与其自身计算相关的所有信息。如果您想要生成器的多个实例,请不要将其设为类方法,就像我答案的后半部分所示。静态函数和静态类存在于许多其他语言中。这不是一些特定于 python 的恶作剧(你应该知道,你在 java 和 c++ 中拥有金徽章) (2认同)

Pyc*_*ath 5

\n

接受随机数生成器作为参数的函数

\n
\n

那么就这样称呼它:

\n
that_function(nrng().__next__)\n
Run Code Online (Sandbox Code Playgroud)\n

或者与functools.partial

\n
that_function(partial(next, nrng()))\n
Run Code Online (Sandbox Code Playgroud)\n

或者没有你的发电机,如果这arange就是你想要的:

\n
that_function(iter(np.arange(1,10.5,0.5)).__next__)\n
Run Code Online (Sandbox Code Playgroud)\n

演示代码(rngnrng你的,我添加了that_function测试调用):

\n
import numpy as np\nfrom functools import partial\n\n# a random number generator\nrng = lambda : np.random.randint(2,20)//2\n\n# a non-random number generator\ndef nrng():\n    numbers = np.arange(1,10.5,0.5)\n    for i in range(len(numbers)):\n        yield numbers[i]\n\ndef that_function(rng):\n    print(*(rng() for j in range(10)))\n\nthat_function(rng)\nthat_function(nrng().__next__)\nthat_function(iter(np.arange(1,10.5,0.5)).__next__)\nthat_function(partial(next, nrng()))\n
Run Code Online (Sandbox Code Playgroud)\n

输出(在线尝试!):

\n
4 6 1 3 8 7 3 6 2 1\n1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5\n1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5\n1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5\n
Run Code Online (Sandbox Code Playgroud)\n