独立的'random'实例

16 投票
3 回答
6794 浏览
提问于 2025-04-15 19:00

下面的代码试图说明我想要的效果。简单来说,我想要两个“随机数生成器”,它们之间互不影响。我希望在一个类里设置“随机数生成器”的种子,而不影响另一个类里的“随机数生成器”。我该怎么做呢?

class RandomSeeded:
    def __init__(self, seed):
        import random as r1
        self.random = r1
        self.random.seed(seed)
    def get(self):
        print self.random.choice([4,5,6,7,8,9,2,3,4,5,6,7,])

class Random:
    def __init__(self):
        import random as r2
        self.random = r2
        self.random.seed()
    def get(self): 
        print self.random.choice([4,5,6,7,8,9,2,3,4,5,6,7,])

if __name__ == '__main__':
    t = RandomSeeded('asdf')
    t.get()       # random is seeded within t
    s = Random()
    s.get()       
    t.get()       # random should still be seeded within t, but is no longer

3 个回答

4

很遗憾,使用两个独立的随机数生成器(RNG)可能比使用一个随机数生成器更不随机,尤其是当你用“偏移量”来处理生成的序列时。

使用“偏移量”意味着你需要先生成完整的样本序列,然后再用这些序列来进行模拟。大概是这样的。

def makeSequences( sequences=2, size=1000000 ):
    g = random.Random()
    return [ [ g.random() for g in xrange(size) ] for s in xrange(sequences) ] ]

t, s = makeSequences( 2 )

随机数生成器的随机性特性只能在使用单一种子和单一序列的情况下得到验证。因为两个并行的序列使用相同的常数来进行乘法和取模运算,所以它们之间可能会有可检测的关联。

7

对于种子随机数,你可以自己创建一个 random.Random 的实例。random 的文档 里详细解释了这个类。当你直接使用模块里的函数时,它只依赖于这个类的一个实例。

24

random.Random 是专门用来实现你想要的功能的——模块本身就是单例的,也就是说每个模块只有一个实例,而类则可以创建多个实例,所以这两种需求都能得到满足。

如果你真的需要一个模块的独立副本(不过在 random 的情况下你肯定不需要!),可以试试用 copy.deepcopy 来处理它——在很多情况下这样做是有效的。不过,这种需求非常少见,因为模块通常不会保存全局可变状态,除非它们保持一个特权的类实例供外部使用(除了 random,还有其他例子,比如 fileinput)。

撰写回答