Python 为什么包装random.random的随机方法似乎会影响RNG?
我试图通过在Python 为什么包装random.random的随机方法似乎会影响RNG?,python,python-3.x,random,Python,Python 3.x,Random,我试图通过在random()周围放置一个包装器来打印内容,从而记录对它的调用。令人惊讶的是,我注意到我开始得到不同的随机值。我创建了一个小示例来演示这种行为: 脚本main.py: import random def not_wrapped(seed): """ not wrapped """ gen = random.Random() gen.seed(seed) # def wrappy(func
random()
周围放置一个包装器来打印内容,从而记录对它的调用。令人惊讶的是,我注意到我开始得到不同的随机值。我创建了一个小示例来演示这种行为:
脚本main.py:
import random
def not_wrapped(seed):
""" not wrapped """
gen = random.Random()
gen.seed(seed)
# def wrappy(func):
# return lambda: func()
# gen.random = wrappy(gen.random)
gen.randint(1, 1)
return gen.getstate()
def wrapped(seed):
""" wrapped """
gen = random.Random()
gen.seed(seed)
def wrappy(func):
return lambda: func()
gen.random = wrappy(gen.random)
gen.randint(1, 1)
return gen.getstate()
for s in range(20):
print(s, not_wrapped(s) == wrapped(s))
python3.7.5 main.py的输出(与python3.6.9相同)
因此,正如您看到的,随机实例gen
的状态不同,这取决于我是否在wrappy
中包装gen.Random
如果我调用randint()
两次,则所有种子0-19的测试都将失败。对于Python 2.7.17,wrapped
和not_wrapped
函数每次都返回相同的随机值(为每个种子打印True)
有人知道发生了什么事吗
Python 3.6在线示例:
在Python3.8.2的这个在线repl上,问题没有显示出来:
(这个问题被交叉发布在:)这个答案是关于Python 3.6的 该状态仅由gen.randint(1,1)调用更改,因此让我们看看它在引擎盖下调用了什么
random.random.randint
的实现:
def randint(self, a, b):
"""Return random integer in range [a, b], including both end points.
"""
return self.randrange(a, b+1)
random.random.randrange
为,它使用random.random.\u randbown
生成随机数
random
方法是否已被重写
...
from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType
...
def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type,
Method=_MethodType, BuiltinMethod=_BuiltinMethodType):
"Return a random int in the range [0,n). Raises ValueError if n==0."
random = self.random
getrandbits = self.getrandbits
# CHECKS IF random HAS BEEN OVERRIDDEN!
# If not, this is the default behaviour:
# Only call self.getrandbits if the original random() builtin method
# has not been overridden or if a new getrandbits() was supplied.
if type(random) is BuiltinMethod or type(getrandbits) is Method:
k = n.bit_length() # don't use (n-1) here because n can be 1
r = getrandbits(k) # 0 <= r < 2**k
while r >= n:
r = getrandbits(k)
return r
# OTHERWISE, it does something different!
# There's an overridden random() method but no new getrandbits() method,
# so we can only use random() from here.
# And then it goes on to use `random` only, no `getrandbits`!
。。。
从类型导入MethodType为_MethodType,从内置MethodType为_内置MethodType
...
def _randbown(self,n,int=int,maxsize=1看起来您是在比较getstate()
的输出,而不是实际的随机输出。在文档中没有任何内容表明应该检查getstate()
。getstate()
的输出仅用作setstate()的输入
call。例如,它可能包含在您的案例中没有实际使用的字段,但为方便起见设置了这些字段,例如,一天中的时间。我实际上不知道引擎盖下发生了什么。@PresidentJamesK.Polk我认为它不包含类似的内容。无论如何,将getstate
替换为对random的调用de>产生相同的输出。所以它在更新的版本中被修复了?那么你担心什么呢?@AlexWeavers我不一定担心,我想知道它为什么会发生-这很有趣,你不认为吗?如果没有人知道,它可能是一个仍然存在或可能再次出现的大版本。而且不是每个人都运行最新的python版本。在我的办公室,我们是在Python3.6上。
...
from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType
...
def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type,
Method=_MethodType, BuiltinMethod=_BuiltinMethodType):
"Return a random int in the range [0,n). Raises ValueError if n==0."
random = self.random
getrandbits = self.getrandbits
# CHECKS IF random HAS BEEN OVERRIDDEN!
# If not, this is the default behaviour:
# Only call self.getrandbits if the original random() builtin method
# has not been overridden or if a new getrandbits() was supplied.
if type(random) is BuiltinMethod or type(getrandbits) is Method:
k = n.bit_length() # don't use (n-1) here because n can be 1
r = getrandbits(k) # 0 <= r < 2**k
while r >= n:
r = getrandbits(k)
return r
# OTHERWISE, it does something different!
# There's an overridden random() method but no new getrandbits() method,
# so we can only use random() from here.
# And then it goes on to use `random` only, no `getrandbits`!