Python random.seed表现得很奇怪

时间:2017-10-04 13:00:00

标签: python random random-seed

我调用random.seed(234),然后调用random.randint(0,99)并收到92.当我再次重复此过程几次时,我收到86.当我第二次调用random.randint然后它返回92.我期待第一个值是86而不是92.为什么它是92?

完整的日志输出如下。我已经包含了所有这些内容,因为之前有一些行动可以解释看似错误的行为:

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)]'

** 编辑,怪异:“相同”看似错误的行为重复 ** 在同一个终端窗口中,我关闭了之前的ipython会话。我做了一些命令行活动,然后我又打开了ipython。我做了一些不同的工作。然后我再试一次:

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

2 个答案:

答案 0 :(得分:8)

这里发生的事情是,IPython系统中的某些东西正在使用@RequestMapping(value = "/images/{imageId}", method = RequestMethod.GET) public ResponseEntity<byte[]> getEventImage(@PathVariable("imageId") String imageId) { 模块,因此消耗核心Mersenne Twister生成器提供的随机流中的数字。这意味着,如果您还使用random模块,则只能看到流中数字的不可预测的子集,因为IPython会完成剩下的工作。

我可以通过在random的调用之间随机点击<Enter>键几次来重现您可靠地看到的效果(在Python 2和Python 3上)(尽管我实际上是#&# 39; m为了简单起见使用random.randint。这是一个示例会话,在macOS 10.12.6上使用Python 3.6.2和IPython 6.2.0。

random.random

要检查我的假设,我通过将以下方法添加到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 类来攻击标准库中Random.random文件中的random.py方法:

Random

现在启动IPython,嘿presto!很多追溯。我不会完全重现这些追溯(他们很长),但是其中一个是尾声:

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

正如您所看到的,IPython使用的prompt_toolkit库使用随机模块来重新排列其任务(尽管最近根据CHANGELOG删除了此更改)。

如果您需要可靠的可重现的随机流,请创建一个明确的 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() 实例并使用它:

random.Random

答案 1 :(得分:-1)

我的Python 2.7.5无法重现相同的行为,但文档  (https://docs.python.org/2/library/random.html)说

  

如果a不是None或int或long,则使用hash(a)代替。   请注意,某些类型的哈希值是不确定的   PYTHONHASHSEED已启用。

我会(只是意见)说它可能是由哈希函数的非确定性行为引起的。您的PYTHONHASHSEED已启用吗?