如何用自己的生成器覆盖Python的随机数?

在Python 的文档中random,它指出可以通过覆盖该random()方法来“使用您自己的基本生成器” 。假设我有一个自定义生成器,它在半开放范围 [0.0, 1.0) 内均匀地输出随机浮点数,即就像random().

  • 我将如何用自己的 Python 替换 Python?

此外,假设替换是一个真正的随机生成器,它建立在一个自然的熵源之上。

  • 这是否意味着我可以像random.choice()在给定数组上一样使用类的其他部分,并声称所选元素是真正随机的?

回答

Python 的random模块实际上是围绕random.Random类型构建的。各种“随机函数”,例如random.random仅使用该类型的默认实例。

要创建自己的随机数生成器,只需子类化random.Random并替换其random 方法即可。虽然对基本功能没有严格要求,但强烈建议调整seed,getstatesetstate方法。

class RangeRandom(Random):
    """
    Example "random" number generator that provides numbers from a uniform sequence
    """
    def __init__(self, resolution=100):
        self._pos = 0
        self._resolution = resolution

    def random(self) -> float:
        self._pos = (self._pos + 1) % self._resolution
        return self._pos / self._resolution

    def getstate(self):
        return self._pos, self._resolution

    def setstate(self, state) -> None:
        self._pos,self._resolution = state

    def seed(self, a) -> None:
        self._pos = int(a) % self._resolution

值得注意的是,定义random方法足以使所有其他方法使用相同的潜在“随机性”。例如,使用choicerandint将基于以下random方法绘制的随机整数:

>>> rand = RangeRandom()
>>> vals = [1, 2, 3, 4]
>>> [rand.choice([1, 2, 3, 4]) for _ in range(5)]
[2, 4, 2, 4, 2, 4]

值得指出的是,虽然实现random足够了random.Random然后使用内部助手将随机浮点数转换为随机整数;这本质上是有损的,因为 float 的精度有限。如果随机数生成器允许,建议也实现_randbelow或至少getrandbits.

random.getrandbits(k)

返回具有 k 个随机位的非负 Python 整数。此方法随 MersenneTwister 生成器提供,其他一些生成器也可以将其作为 API 的可选部分提供。当可用时, getrandbits() 使 randrange() 能够处理任意大的范围。

未记录的方法_randbelow必须接受一个整数n并返回一个区间内的随机整数[0, n)

class ArbitraryRangeRandom(RangeRandom):
    """
    Example "random" number generator for floats/ints from a uniform sequence
    """
    def _randbelow(self, n: int) -> int:
        self.random()  # advance the RNG
        if n == 0:
            return 0
        elif n <= self._resolution:
            return self._pos % n
        else:
            return self._pos * (n // self._resolution)
>>> rand = RangeRandom()
>>> vals = [1, 2, 3, 4]
>>> # explicit int support provides better resolution/spacing
>>> print([rand.choice([1, 2, 3, 4]) for _ in range(5)])
[2, 3, 4, 1, 2]


以上是如何用自己的生成器覆盖Python的随机数?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>