简体   繁体   English

Python random.seed表现得很奇怪

[英]Python random.seed behaved strangely

I called random.seed(234), then called random.randint(0, 99) and received 92. When I repeated this process again several times I received 86. When I called random.randint a second time then it return 92. I was expecting the first value to be 86 not 92. Why was it 92? 我调用random.seed(234),然后调用random.randint(0,99)并收到92.当我再次重复此过程几次时,我收到86.当我第二次调用random.randint然后它返回92.我期待第一个值是86而不是92.为什么它是92?

The full log output is below. 完整的日志输出如下。 I've included all of it incase there was some previous action that can explain the seemingly buggy behaviour: 我已经包含了所有内容,因为之前有一些行动可以解释看似错误的行为:

In [1]: import random

In [2]: import string

In [3]: string.letters
Out[3]: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

In [4]: string.ascii_letters
Out[4]: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

In [5]: string.printable
Out[5]: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

In [6]: len(string.printable)
Out[6]: 100

In [7]: [string.printable[random.randint(0,99)] for i in range(20)]
Out[7]: 
['{',
'+',
'[',
'\r',
'R',
'Z',
'v',
'|',
'v',
'e',
'T',
'x',
'\\',
'}',
'0',
'>',
'V',
'\n',
'`',
'`']

In [8]: ''.join([string.printable[random.randint(0,99)] for i in range(20)])
Out[8]: '%Z\\%mx4Z53uUZIa5KHe*'

In [9]: ''.join([string.printable[random.randint(0,99)] for i in range(20)])
Out[9]: 'Fg\nDHW+oV?-9``}\x0by%xD'

In [10]: import os

In [11]: os.urandom(1)
Out[11]: '('

In [12]: os.urandom(1)
Out[12]: '8'

In [13]: os.urandom(1)
Out[13]: '\xb1'

In [14]: os.urandom(1)
Out[14]: ')'

In [15]: os.urandom(1)
Out[15]: '\x8c'

In [16]: os.urandom(1)
Out[16]: '^'

In [17]: os.urandom(1)
Out[17]: '{'

In [18]: os.urandom(1)
Out[18]: '\x8f'

In [19]: ''.join(os.urandom(10))
Out[19]: '{t\x8dR\x1d\x83\xef\xd6N\xbd'

In [20]: ''.join(os.urandom(10))
Out[20]: '\x96\\\xf6\xe3\xf4/\x1f\xc7\x90\x02'

In [21]: from random import SystemRandom

In [22]: crypt = SystemRandom()

In [23]: ''.join([string.printable[crypt.randrange(100)] for i in range(20)])
Out[23]: "WoDVH\r1!?1+djB'f<;nW"

In [24]: ''.join([string.printable[crypt.randrange(100)] for i in range(20)])
Out[24]: '\rf?zo`7^{Y_Zx^[SYw7c'

In [25]: ''.join([string.printable[crypt.randrange(100)] for i in range(20)])
Out[25]: "3k*uGVIP'~^{P*~bserk"

In [26]: ''.join([string.printable[crypt.randrange(100)] for i in range(20)])
Out[26]: '~lkM/a&#_F&D\n<sC&i\r\n'

In [27]: random.seed(234)

In [28]: random.randint(0,99)
Out[28]: 92

In [29]: random.seed(234)

In [30]: random.randint(0,99)
Out[30]: 86

In [31]: random.seed(234)

In [32]: random.randint(0,99)
Out[32]: 86

In [33]: random.seed(234)

In [34]: random.randint(0,99)
Out[34]: 86

In [35]: random.randint(0,99)
Out[35]: 92

In [36]: random.randint(0,99)
Out[36]: 48

In [37]: random.seed(234)

In [38]: random.randint(0,99)
Out[38]: 86

In [39]: import sys

In [40]: sys.version_info
Out[40]: sys.version_info(major=2, minor=7, micro=13, releaselevel='final', serial=0)

In [41]: sys.version
Out[41]: '2.7.13 (default, Dec 17 2016, 23:03:43) \n[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]'

** edit, weird: "same" seemingly buggy behaviour repeated ** In the same terminal window I closed the previous ipython session. ** 编辑,怪异:“相同”看似错误的行为重复 **在同一个终端窗口中,我关闭了之前的ipython会话。 I did some command line activity, then I opened ipython again. 我做了一些命令行活动,然后我又打开了ipython。 I did some different work. 我做了一些不同的工作。 Then I tried this again: 然后我再试一次:

In [37]: import random

In [38]: random.seed(234)

In [39]: random.randint(0, 99)
Out[39]: 85

In [40]: random.randint(0, 99)
Out[40]: 50

In [41]: random.seed(234)

In [42]: random.randint(0, 99)
Out[42]: 86

In [43]: random.randint(0, 99)
Out[43]: 92

What's happening here is that something in the IPython system is making use of the random module, and so consuming numbers from the random stream provided by the core Mersenne Twister generator. 这里发生的事情是IPython系统中的某些东西正在利用random模块,因此消耗核心Mersenne Twister生成器提供的随机流中的数字。 That means that if you're also using the random module, you only see an unpredictable subset of the numbers from the stream, since IPython gets the rest. 这意味着如果你也使用random模块,你只能从流中看到一个不可预测的数字子集,因为IPython得到了其余的。

I can reproduce the effect you're seeing reliably (on both Python 2 and Python 3) by hitting the <Enter> key a few times randomly between invocations of random.randint (though actually I'm using random.random for simplicity). 我可以通过在random.randint调用之间随机点击<Enter>键几次来重现你可靠地看到的效果(在Python 2和Python 3上)(尽管实际上我使用random.random来简化)。 Here's one example session, with Python 3.6.2 and IPython 6.2.0 on macOS 10.12.6. 这是一个示例会话,在macOS 10.12.6上使用Python 3.6.2和IPython 6.2.0。

In [1]: import random

In [2]: random.seed(234)

In [3]: 

In [3]: 

In [3]: random.random()
Out[3]: 0.8579160018299248

In [4]: random.random()
Out[4]: 0.5055065431394443

In [5]: random.seed(234)

In [6]: random.random()
Out[6]: 0.26476014305349627

In [7]: random.random()
Out[7]: 0.8579160018299248

In [8]: random.random()
Out[8]: 0.5055065431394443

To check my hypothesis, I hacked in an override to the Random.random method in the random.py file in the standard library, by adding the following method to the Random class: 为了检查我的假设,我通过在Random类中添加以下方法来修改标准库中random.py文件中的Random.random方法:

def random(self):
    print("random being called")
    import traceback; traceback.print_stack()
    return super(Random, self).random()

Now launch IPython, and hey presto! 现在启动IPython,嘿presto! Lots of tracebacks. 很多追溯。 I won't reproduce the tracebacks in full (they're long), but here's the tail end of one of them: 我不会完全重现回溯(它们很长),但这里是其中一个的尾端:

  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/terminal/interactiveshell.py", line 376, in prompt_for_code
    pre_run=self.pre_prompt, reset_current_buffer=True)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/prompt_toolkit/interface.py", line 415, in run
    self.eventloop.run(self.input, self.create_eventloop_callbacks())
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/prompt_toolkit/eventloop/posix.py", line 157, in run
    random.shuffle(tasks)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/random.py", line 278, in shuffle
    j = randbelow(i+1)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/random.py", line 250, in _randbelow
    r = random()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/random.py", line 98, in random
    import traceback; traceback.print_stack()

As you can see, the prompt_toolkit library, which is used by IPython, uses the random module to shuffle its tasks (though this change was recently removed, according to the CHANGELOG ). 正如您所看到的,IPython使用的prompt_toolkit库使用随机模块来重新调整其任务(尽管最近根据CHANGELOG删除了此更改)。

If you need a reliably reproducible random stream, create an explicit random.Random instance and use that: 如果您需要可靠的可重现的随机流,请创建一个显式的random.Random实例并使用:

In [1]: from random import Random

In [2]: my_random = Random()

In [3]: my_random.seed(234)

In [4]: my_random.randint(0, 99)
Out[4]: 43

In [5]: my_random.randint(0, 99)
Out[5]: 33

In [6]: my_random.seed(234)

In [7]: my_random.randint(0, 99)
Out[7]: 43

In [8]: my_random.randint(0, 99)
Out[8]: 33

My Python 2.7.5 can not reproduce the same behavior, but the documentation ( https://docs.python.org/2/library/random.html ) says 我的Python 2.7.5无法重现相同的行为,但文档( https://docs.python.org/2/library/random.html )说

If a is not None or an int or a long, then hash(a) is used instead. 如果a不是None或者是int或long,则使用hash(a)代替。 Note that the hash values for some types are nondeterministic when PYTHONHASHSEED is enabled. 请注意,启用PYTHONHASHSEED时,某些类型的哈希值是不确定的。

I would (just opinion) say that it can be caused by the nondeterministic behavior of the hash function. 我会(只是意见)说它可能是由哈希函数的非确定性行为引起的。 Is your PYTHONHASHSEED enabled? 您的PYTHONHASHSEED已启用吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 python 3:random.seed():在哪里调用它? - python 3: random.seed(): where to call it? 为什么 python random.seed 在非原始输入上是不确定的? - Why is python random.seed nondeterministic on non-primative inputs? Python random.seed() 和 numpy.random.seed() 实现是否彼此不同? - Does Python random.seed() and numpy.random.seed() implementations differ one from another? 随机数的生成和random.seed()的使用 - Generation of random numbers and the use of random.seed() Python random.seed 在 python 中产生相似的 random.randint 数给定不同的范围大小 - Python random.seed produces similar random.randint numbers in python given different range sizes 如何在Python中使用random.seed创建多个不同的初始伪随机数? - How to use random.seed to create multiple different initial pseudo random numbers in Python? random.seed():它有什么作用? - random.seed(): What does it do? 尝试为每个循环+1到random.seed() - trying to +1 to random.seed() for every loop 在 Python 中使用 Random.seed()、&#39;for&#39; 和乘法输出 30-35 之间的随机数 - Output random number between 30-35 using Random.seed(), 'for' and multiplication in Python python 中的 random.seed function 如何用于文字? 它转换成什么数字? - How does the random.seed function in python work for words? What number is it converted to?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM