我调用了 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/