如何查询random.random()使用的种子?
有没有办法知道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
的结果可以被序列化,如果你想要永久保存它的话。
75
从生成器中无法自动获取种子值。我通常是这样生成种子的:
seed = random.randrange(sys.maxsize)
rng = random.Random(seed)
print("Seed was:", seed)
这种方法是基于时间的,所以每次你手动运行这个脚本时,生成的种子都会不同。不过,如果你使用多个生成器,它们的种子值不会相同,因为它们几乎是同时创建的。