继承random.Random类后同种子生成不同随机结果的问题
问题:重写random.Random的random()方法为何改变随机序列?
初始代码与预期输出
当我们直接继承random.Random且不修改任何方法时,相同种子会生成一致的随机序列:
import random class MyRandom(random.Random): pass r = random.Random() r.seed(10) print(r.randint(0, 20)) print(r.randint(0, 20)) print(r.randint(0, 20)) print("------------") r2 = MyRandom() r2.seed(10) print(r2.randint(0, 20)) print(r2.randint(0, 20)) print(r2.randint(0, 20))
输出:
18 1 13 ------------ 18 1 13
修改后的代码与意外输出
但当我们重写random()方法(哪怕只是调用父类的实现),相同种子的随机序列却发生了变化:
import random class MyRandom(random.Random): def random(self): return super().random() r = random.Random() r.seed(10) print(r.randint(0, 20)) print(r.randint(0, 20)) print(r.randint(0, 20)) print("------------") r2 = MyRandom() r2.seed(10) print(r2.randint(0, 20)) print(r2.randint(0, 20)) print(r2.randint(0, 20))
输出:
18 1 13 ------------ 20 9 6
原因解释
这是CPython中random.Random的内部实现逻辑导致的:
randint方法底层依赖randrange,而randrange有两种生成随机数的路径:- 如果子类没有重写
random(),会优先使用_getrandbits方法来生成随机数,这个路径的状态流转和父类完全一致,所以相同种子输出相同序列。 - 一旦子类重写了
random(),哪怕只是简单转发父类的实现,CPython会默认子类可能未正确实现配套的_getrandbits方法,于是randrange会切换到另一种基于random()的实现逻辑——这个逻辑的随机数生成步骤和_getrandbits路径不同,哪怕种子相同,最终输出的序列也会不一样。
- 如果子类没有重写
而直接调用random()时,不管有没有重写,都是直接调用父类的random()方法,状态流转完全一致,所以输出不会有差异。
内容的提问来源于stack exchange,提问作者MarcTheSpark
相关产品推荐
相关产品推荐

