2017-10-04 8 views
4

Ich rief random.seed (234), dann random.randint (0, 99) und erhielt 92. Wenn ich diesen Prozess mehrmals wiederholt habe ich 86. Wenn ich random.randint aufgerufen ein zweites Mal, dann 92. Ich habe erwartet, dass der erste Wert 86 und nicht 92 ist. Warum war es 92?Python random.seed verhielt sich seltsam

Die vollständige Protokollausgabe ist unten. Ich habe alle davon enthalten einhüllen dort einige vorherige Aktion war, das scheinbar fehlerhaftes Verhalten erklären kann:

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

** bearbeiten, seltsam: „same“ scheinbar fehlerhaftes Verhalten ** Im gleichen Endgerät wiederholt Fenster Ich habe die vorherige ipython-Sitzung geschlossen. Ich habe einige Befehlszeilenaktivitäten ausgeführt, dann habe ich Ipython erneut geöffnet. Ich habe eine andere Arbeit gemacht. Dann habe ich versucht, diese wieder:

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

Python 3.4 '>>> zufällig.Samen (234) >>> random.randint (0, 99) >>> random.seed (234) >>> random.randint (0, 99) >>> random.seed (234) >>> random.randint (0, 99) 43'. Kann nicht reproduzieren. –

+0

getestet mit Python 2.7, unterschiedlicher Wert, aber immer gleich auch ... –

+0

Ja, seltsam, huh. Danke @ Jean-FrançoisFabre, ich schätze, das ist ein Randfallfehler oder ein dokumentiertes, aber überraschendes Verhalten. – AJP

Antwort

7

Was hier passiert ist, dass etwas im IPython-System das Modul random nutzt und so Zahlen aus dem Zufallsstrom des Kern Mersenne Twister-Generator verbraucht. Das heißt, wenn Sie auch das Modul random verwenden, sehen Sie nur eine unvorhersehbare Teilmenge der Zahlen aus dem Stream, da IPython den Rest erhält.

ich die Wirkung reproduzieren können Sie zuverlässig zu sehen sind (sowohl Python 2 und Python 3) durch die <Enter> Taste ein paar Mal zufällig zwischen Anrufungen von random.randint schlagen (obwohl eigentlich bin ich random.random der Einfachheit halber verwendet wird). Hier ist eine Beispielsitzung mit Python 3.6.2 und IPython 6.2.0 unter macOS 10.12.6.

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 

meine Hypothese zu überprüfen, die ich in einer Überschreibung der Random.random Methode in der random.py Datei in der Standardbibliothek gehackt, indem Sie die folgende Methode die Random Klasse hinzufügen:

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

Jetzt IPython starten und hey presto! Viele Rückverfolgungen. Ich werde nicht die Tracebacks vollständig reproduzieren (sie sind lang), aber hier ist das hintere Ende eines von ihnen:

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

Wie Sie sehen können, die prompt_toolkit Bibliothek, die von IPython verwendet wird, verwendet das zufälliges Modul zum Mischen seiner Aufgaben (obwohl diese Änderung kürzlich entfernt wurde, gemäß der CHANGELOG).

Wenn Sie einen zuverlässig reproduzierbaren Zufallsstrom benötigen, eine explizite random.Random Instanz erstellen und verwenden:

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

Interessant und beängstigend zugleich! Und schöne Analyse. – sascha

-1

Mein Python 2.7.5 nicht das gleiche Verhalten reproduzieren können, aber die Dokumentation (https://docs.python.org/2/library/random.html) sagt

Wenn ein nicht Keine oder ein int oder lang , dann wird stattdessen Hash (a) verwendet. Beachten Sie, dass die Hashwerte für einige Typen nicht deterministisch sind, wenn PYTHONHASHSEED aktiviert ist.

Ich würde (nur Meinung) sagen, dass es durch das nichtdeterministische Verhalten der Hash-Funktion verursacht werden kann. Ist Ihr PYTHONHASHSEED aktiviert?

+0

Wie erzählst du? Ich habe '' PYTHONHASHSEED 'in os.environ' und '' False' bekommen. – AJP

+0

Dies sollte hier nicht gelten: 'PYTHONHASHSEED' hat keinen Einfluss auf die Art und Weise, in der Hash-Werte integer sind. –