Python27:setstate()后面的random()不';t产生相同的随机数

Python27:setstate()后面的random()不';t产生相同的随机数,python,python-2.7,random,Python,Python 2.7,Random,我一直在对Python的随机数生成器进行子类化,以生成一个不重复结果的生成器(它将用于为模拟器生成唯一的id),我只是在测试它在从先前状态加载后的行为是否一致 在人们提问之前: 这是一个单身班 不,没有其他任何东西应该使用该实例(拆下后会看到) 是的,我在没有检查singleton实例的情况下测试了它 是的,当我创建这个子类时,我确实调用了一个新实例(super(nrand,self)。\uuuu init\uuu()) 是的,根据另一篇文章,我应该得到一致的结果,见: 下面是我的测试代码:

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

在人们提问之前:

  • 这是一个单身班
  • 不,没有其他任何东西应该使用该实例(拆下后会看到)
  • 是的,我在没有检查singleton实例的情况下测试了它
  • 是的,当我创建这个子类时,我确实调用了一个新实例(
    super(nrand,self)。\uuuu init\uuu()
  • 是的,根据另一篇文章,我应该得到一致的结果,见:
下面是我的测试代码:

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])
类单例(类型):
_实例={}
定义调用(self,*args,**kwargs):
如果self不在self.\u实例中:
self.\u实例[self]=super(单例,self)。\u调用(*args,**kwargs)
返回self.\u实例[self]
类别nrRand(随机):
__元类\单例
'''
类文档
'''
定义初始化(自):
'''
建造师
'''
超级(nRand,self)。\uuuu init\uuuuuu()
self.previous=[]
def随机(自):
n=super(nrand,self).random()
而n在self.previous中:
n=super(nrand,self).random()
self.previous.append(n)
返回n
def种子(自身,x):
如果x为无:
x=长(time.time()*1000)
self.previous=[]
计数=x
nSeed=0
当计数小于0时:
nSeed=super(nrand,self).random()
计数-=1
超级(nRand,self).种子(NSED)
当NSED<0时:
超级(nRand,self).种子(NSED)
计数-=1
def getstate(自身):
返回(self.previous,super(nrand,self.getstate())
def设置状态(自身、状态):
self.previous=状态[0]
超级(nRand,self).setstate(状态[1])

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

更新:

    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)

我应该提到的是,当我设置并获得状态时,我会确保重置该列表。啊,非常感谢你犯了这样一个简单而愚蠢的错误。你能分享你的子类吗?您是否在没有子类的情况下进行了测试?直接在
random
模块上使用测试代码会产生预期的输出,所以错误就在你的代码中。@MartijnPieters:不,我没有这样做,因为我的工作假设链接帖子的行为仍然成立,并且我对随机数生成器在大多数情况下的工作方式有偏见(即使用相同的起始种子,你应该得到相同的数字集)。不管怎样,我已经共享了我的子类。所以,如果您恢复
self.previous
,为什么您希望它生成两个相同的值?