現有答案在處理問題的具體問題方面做得很好,但我認爲值得一提的是一個側面問題:爲什麼你特別想要通過替代「隨機生成器」到shuffle
而不是其他的函數random
模塊。引述the docs:
注意,對於即使相當小 LEN(x)中,的x的 排列的總數大於所述 期間最隨機數 發生器較大;這意味着永遠不會產生長序列的大部分排列 。
短語「隨機數生成器」在這裏指的是什麼,可以更迂腐稱爲僞 -random數發生器 - 發電機,讓隨機性好模仿,但完全是算法,因此被稱爲不是是「真正的隨機」。任何這樣的算法都會有一個「時期」 - 最終會開始重演。
Python的random
模塊採用了特別好的和充分研究的僞隨機數發生器,該Mersenne Twister,用了一段2**19937-1
- 數字時在十進制數字寫出有超過6000位數字,如len(str(2**19937-1))
將確認;-)。在我的筆記本電腦,我可以每秒產生大約500萬這樣的數字:
$ python -mtimeit -s'import random' 'random.random()'
1000000 loops, best of 3: 0.214 usec per loop
假設更快的機器,能產生每秒十億這樣的數字,該週期將需要約10 年到重複 - 並且宇宙年齡的最佳當前估計值比1.5 * 10 年少。因此,宇宙生命週期幾乎不可思議的達到重複的地步;-)。平行計算並沒有多大幫助;估計宇宙中有大約10個原子,所以即使你能夠在宇宙中的每個原子上運行這樣一個每秒十億次的發生器,它仍然需要超過10個宇宙 - 生活時間開始重複。
所以,你可能有理由懷疑這種擔心重複是理論而非實際問題的一小部分;-)。儘管如此,因式分解(計算長度序列N的排列)也增長得相當快。 Mersenne Twister,例如,可能能夠產生長度爲2080的序列的所有排列,但絕對不是長度爲2081或更高的排列。如果不是「宇宙的一生」問題,那麼文檔擔心「甚至小len(x)」是合理的 - 我們知道,許多可能的置換永遠不可能通過用這樣的僞-RNG,只要我們有一個相當長的序列,因此人們可能會擔心什麼樣的偏見我們實際上甚至幾洗牌!:介紹 - )
os.urandom介導訪問的物理任何來源操作系統提供的隨機性 - Windows上的CryptGenRandom,Linux上的/dev/urandom等。os.urandom
給出了字節序列,但藉助struct很容易使它們變成隨機數字:
>>> n = struct.calcsize('I')
>>> def s2i(s): return struct.unpack('I', s)[0]
...
>>> maxi = s2i(b'\xff'*n) + 1
>>> maxi = float(s2i(b'\xff'*n) + 1)
>>> def rnd(): return s2i(os.urandom(n))/maxi
現在,我們可以調用random.shuffle(somelist, rnd)
和少擔心偏見;-)。
不幸的是,測量表明,這種方法對於RNG比調用random.random()
要慢50倍 - 如果我們需要很多隨機數(這可能是一個重要的實際考慮因素(如果我們不需要,擔心可能的偏見可能會錯位;-)。 os.urandom
方法也很難以可預測的,可重複的方式使用(例如,用於測試目的),而random.random()
只需在測試開始時提供一個固定的初始random.seed
以保證可重複的行爲。
因此,在實踐中,os.urandom
僅用於需要「密碼質量」隨機數字 - 確定的攻擊者無法預測的數字 - 因此願意支付使用該數字的實際價格而不是random.random
。
嗨,我只是用一個額外的聲明更新我的文章。所以我想這個額外的參數正好是1和0之間的概率(不包括1) – CppLearner 2009-12-25 15:41:24
否,附加參數是返回僞隨機數的**函數**,它本身不是數字。 Python允許函數作爲參數傳遞到其他函數,這是一個很好的顯示這樣的能力 – 2009-12-25 15:44:02