Python random.seed 表现异常

标签 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 session 。我做了一些命令行事件,然后我再次打开了 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

最佳答案

这里发生的事情是 IPython 系统中的某些东西正在使用 random模块,因此使用核心 Mersenne Twister 生成器提供的随机流中的数字。这意味着如果您还使用 random模块,您只能从流中看到不可预测的数字子集,因为 IPython 会获取其余部分。

我可以通过点击 <Enter> 可靠地重现您看到的效果(在 Python 2 和 Python 3 上)在调用 random.randint 之间随机键入几次(尽管实际上我为简单起见使用了 random.random)。这是一个示例 session ,在 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

为了验证我的假设,我入侵了对 Random.random 的覆盖random.py 中的方法标准库中的文件,通过将以下方法添加到 Random类:

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

现在启动 IPython,嘿!很多回溯。我不会完整地重现回溯(它们很长),但这是其中一个的尾端:

  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()

如您所见, prompt_toolkit IPython 使用的库使用随机模块来打乱其任务(尽管根据 CHANGELOG 最近删除了此更改)。

如果你需要一个可靠的可重现的随机流,创建一个显式的 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

关于Python random.seed 表现异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46565543/

相关文章:

python - IOError : [Errno 13]

php - 1对1随机配对

perl - List::Util 'shuffle' 实际上是如何工作的?

javascript - 在 JavaScript 中仅随机选择特定数组

python - 读取 jupyter 笔记本的随机种子

python - 在同一程序中播种 random 和 numpy.random 的最佳实践

python - python中根据一段时间生成一些 "random"开始时间供脚本运行

python - 干刮(py): 'Operation on socket not supported'

python - 列表列表中的组合

python - 消除列表的重复项 (Python)