Python27:setstate()之后的random()不会产生相同的随机数

时间:2013-12-28 23:20:29

标签: python python-2.7 random

我一直在继承Python的随机数生成器,以生成一个不重复结果的生成器(它将用于为模拟器生成唯一的id)而我只是在测试它是否在从预先状态加载后的行为是否一致

在人们问之前:

  • 这是一个单身课程
  • 没有其他任何应该使用该实例的东西(一个拆卸看到的那个)
  • 是的,我在没有单例实例的情况下测试了它
  • 并且当我创建这个子类时,我确实调用了一个新实例(super(nrRand,self).__init__()
  • 是的,根据另一篇文章,我应该得到一致的结果,请参阅:Rolling back the random number generator in python?

以下是我的测试代码:

def test_stateSavingConsitantcy(self):
    start = int(self.r.random())
    for i in xrange(start):
        self.r.random()
    state = self.r.getstate()
    next = self.r.random()
    self.r.setstate(state)
    nnext = self.r.random()
    self.assertEqual(next, nnext, "Number generation not constant got {0} expecting {1}".format(nnext,next))

可以提供的任何帮助都非常感谢

编辑:

这是我要求的子类

class Singleton(type):
    _instances = {}
    def __call__(self, *args, **kwargs):
        if self not in self._instances:
            self._instances[self] = super(Singleton,self).__call__(*args,**kwargs)
        return self._instances[self]

class nrRand(Random):
    __metaclass__ = Singleton
    '''
    classdocs
    '''


    def __init__(self):
        '''
        Constructor
        '''
        super(nrRand,self).__init__()
        self.previous = []

    def random(self):
        n = super(nrRand,self).random()
        while n in self.previous:
            n = super(nrRand,self).random()
        self.previous.append(n)
        return n


    def seed(self,x):
        if x is None:
            x = long(time.time()*1000)
        self.previous = []
        count = x
        nSeed = 0
        while count < 0:
            nSeed = super(nrRand,self).random()
            count -= 1
        super(nrRand,self).seed(nSeed)

        while nSeed < 0:
            super(nrRand,self).seed(nSeed)
            count -= 1

    def getstate(self):
        return (self.previous, super(nrRand,self).getstate())

    def setstate(self,state):
        self.previous = state[0]
        super(nrRand,self).setstate(state[1])

1 个答案:

答案 0 :(得分:2)

getstatesetstate仅操纵Random班级所知的状态;两种方法都不知道您还需要回滚先前生成的数字集。您正在回滚从Random继承的状态,但随后该对象看到它已经生成了下一个数字并跳过它。如果您希望getstatesetstate正常工作,则必须覆盖它们以设置已生成数字集的状态。

更新:

    def getstate(self):
        return (self.previous, super(nrRand,self).getstate())

这不应该直接使用self.previous。由于您没有制作副本,因此您将返回用于跟踪已生成数字的实际对象。当RNG产生新号码时,getstate返回的状态反映新号码。您需要复制self.previous,如下所示:

    def getstate(self):
        return (self.previous[:], super(nrRand, self).getstate())

我还建议您在setstate

中制作副本
    def setstate(self, state):
        previous, parent_state = state
        self.previous = previous[:]
        super(nrRand, self).setstate(parent_state)