在随机.Random(python /CPython 2.6)中子类化的问题

4 投票
1 回答
865 浏览
提问于 2025-04-16 12:42
def __init__(self,  (min,  max)):

我在 CPython 2.6(原版 Python 实现)中试过这段代码:

from random import Random, random

class Uniform(Random, object):
    def __init__(self,  min,  max):
        self._min =min
        self._max =max
    def randint(self):
        return super(Uniform, self).randint (self._min,  self._max)
    def uniform(self):
        return super(Uniform, self).uniform(self._min,  self._max)

if __name__ == '__main__':
    a=Uniform(0.,  1.2)
    print a.uniform()
    print a.randint()

虽然看起来这是一种正确的 Python 继承方式,但却出现了这个错误:

/tmp/source.py in <module>()
     11 
     12 if __name__ == '__main__':
---> 13   a=Uniform(0.,  1.2)
     14   print a.uniform()
     15   print a.randint()

TypeError: seed expected at most 1 arguments, got 2
WARNING: Failure executing file: </tmp/source.py>

不过,如果你这样定义:

def __init__(self,  min,  max):

就会奇迹般地“正确”运行……但所有 Uniform 类的实例生成的第一个随机数总是相同的(因为初始种子是一样的!)。

问题来源

random.Random 类是新式类,绝对不是基本类(可以查看 Unix 上的 /usr/lib/python2.6/random.py 和 Windows 上的对应文件)。所以关于内置类的子类化的技巧——我们会在课程中讨论。尽管 random.Random 类是新式的,但它的子类最初是用 C 写的(在 /usr/lib/python2.6/random.py 中可以看到 import _random - 它是一个内置类!)。

这意味着什么呢?我们需要像处理内置类一样重写 __new__ 方法(更多内容可以查看这里:子类化内置类型的问题)。

最终解决方案简述

只需添加对 __new__ 方法的重写(random() 在这个“问题”的第二行被导入,实际上是一个在后台传递给 random.Random.seed(x) 的对象,用于初始化对象的种子(在 /usr/lib/python2.6/random.py 的源代码中))。

class Uniform(Random, object):
    def __new__(cls, *args, **kwargs):
        return super (Uniform, cls).__new__ (cls, random() )
    def __init__(self,  min,  max):
        self._min =min
        self._max =max

享受 Python 中内置的梅森旋转随机数生成器吧 ;-) 祝你好运!

1 个回答

0

你需要在你的构造函数开始时调用 Random.__init__(self, seed)(这里的 seed 参数是可选的):

def __init__(self,  min,  max):
    Random.__init__(self)  # Use the default seed.
    self._min =min
    self._max =max

另外,我不太明白你为什么还要特别去扩展 object; 扩展 Random 就够了。

撰写回答