在随机.Random(python /CPython 2.6)中子类化的问题
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
就够了。