如何查询random.random()使用的种子?

70 投票
7 回答
58074 浏览
提问于 2025-04-16 11:54

有没有办法知道Python用什么种子来初始化它的随机数生成器呢?

我知道我可以自己指定种子,但我其实挺喜欢让Python自己管理这个。不过,我想知道它用了什么种子,这样如果我在某次运行中得到了我喜欢的结果,我就可以在以后重复这个运行。如果我知道当时用的种子,我就能做到这一点。

如果答案是我不能知道,那我自己生成种子的最佳方法是什么呢?我希望每次运行的种子都不一样——我只是想知道到底用了什么种子。

7 个回答

23

你可以创建一个新的类,继承自random.Random,然后重写seed()这个方法,跟Python 3.5的做法一样,只是在调用super()之前,把种子值存储在一个变量里:

    import random

    class Random(random.Random):
        def seed(self, a=None, version=2):
            from os import urandom as _urandom
            from hashlib import sha512 as _sha512
            if a is None:
                try:
                    # Seed with enough bytes to span the 19937 bit
                    # state space for the Mersenne Twister
                    a = int.from_bytes(_urandom(2500), 'big')
                except NotImplementedError:
                    import time
                    a = int(time.time() * 256) # use fractional seconds

            if version == 2:
                if isinstance(a, (str, bytes, bytearray)):
                    if isinstance(a, str):
                        a = a.encode()
                    a += _sha512(a).digest()
                    a = int.from_bytes(a, 'big')

            self._current_seed = a
            super().seed(a)

        def get_seed(self):
            return self._current_seed

如果你测试一下,第一次用新的种子生成的随机值和第二次用同样的种子(通过我们创建的get_seed()方法)生成的值是一样的:

    >>> rnd1 = Random()
    >>> seed = rnd1.get_seed()
    >>> v1 = rnd1.randint(1, 0x260)
    >>> rnd2 = Random(seed)
    >>> v2 = rnd2.randint(1, 0x260)
    >>> v1 == v2
    True

如果你保存或复制这个很大的种子值,并在另一个会话中使用它,生成的值将完全相同。

40

随机数生成器的状态并不总是简单的一个种子值。例如,一个安全的伪随机数生成器(PRNG)通常会有一个熵缓冲区,这其实是一个更大的数据块。

不过,你可以保存和恢复整个随机数生成器的状态,这样你就可以在以后重现它的结果:

import random

old_state = random.getstate()
print random.random()

random.setstate(old_state)
print random.random()

# You can also restore the state into your own instance of the PRNG, to avoid
# thread-safety issues from using the default, global instance.
prng = random.Random()
prng.setstate(old_state)
print prng.random()

当然,getstate的结果可以被序列化,如果你想要永久保存它的话。

http://docs.python.org/library/random.html#random.getstate

75

从生成器中无法自动获取种子值。我通常是这样生成种子的:

seed = random.randrange(sys.maxsize)
rng = random.Random(seed)
print("Seed was:", seed)

这种方法是基于时间的,所以每次你手动运行这个脚本时,生成的种子都会不同。不过,如果你使用多个生成器,它们的种子值不会相同,因为它们几乎是同时创建的。

撰写回答