2017-10-04 101 views
4

我叫random.seed(234),然後調用random.randint(0,99),並收到92.當我再次重複這個過程多次我收到86.當我打電話random.randint第二次然後它返回92.我期待的第一個值是86而不是92.爲什麼是92?Python random.seed表現奇怪

完整的日誌輸出如下。我已經包括它的所有櫃面有以前的一些動作可以解釋看似錯誤行爲:

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]: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>[email protected][\\]^_`{|}~ \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 
+1

蟒蛇3.4'>>>隨機的。種子(234) >>> random.randint(0,99) >>> random.seed(234) >>> random.randint(0,99) >>> random.seed( 234) >>> random.randint(0,99) 43'。無法重現。 –

+0

python 2.7測試,不同的值,但每次都相同... –

+0

是的,很奇怪。謝謝@ Jean-FrançoisFabre,我想這是一個邊緣案例錯誤或記錄但令人驚訝的行爲。 – AJP

回答

7

這裏發生的事情是,IPython系統中的某些東西正在使用random模塊,並且消耗了由核心Mersenne Twister生成器提供的隨機流中的數字。這意味着,如果您還使用random模塊,則只會看到流中數字的不可預知的子集,因爲IPython會獲取其餘部分。

我可以重現你被擊中<Enter>鍵幾次隨機的random.randint調用之間可靠地看到(雙方的Python 2和Python 3)的效果(儘管實際上我使用random.random爲簡單起見)。這是一個示例會話,在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 ,嘿presto!很多追溯。我不會重現全面的回溯(他們長),但這裏的其中之一的尾部:

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 
+0

同時有趣又可怕!還有很好的分析。 – sascha

-1

我的Python 2.7.5無法重現相同的行爲,但文檔 (https://docs.python.org/2/library/random.html)說

如果不是無或int或長,那麼使用散列(a)來代替。 請注意,當啓用 PYTHONHASHSEED時,某些類型的散列值不確定。

我會(只是意見)說,它可能是由哈希函數的非確定性行爲造成的。你的PYTHONHASHSEED是否啓用?

+0

你怎麼看?我在os.environ做了'PYTHONHASHSEED'並得到了'False'。 – AJP

+0

這不應該在這裏適用:'PYTHONHASHSEED'不影響整數散列的方式。 –