Существующие ответы хорошо справляются с конкретной задачей вопроса, но я думаю, что стоит упомянуть побочный вопрос: почему вы, скорее всего, захотите передать альтернативный «генератор случайных чисел» shuffle
, а не другим функциям в модуле random
. Цитируя документы :
Обратите внимание, что даже для довольно небольших
len (x), общее количество
перестановки х больше, чем
период наибольшего случайного числа
генераторы; это означает, что большинство
перестановки длинной последовательности могут
никогда не будет сгенерировано.
Фраза «генераторы случайных чисел» здесь относится к тому, что может быть более педантично названо псевдо - генераторами случайных чисел - генераторами, которые дают хорошую имитацию случайности, но являются полностью алгоритмическими, и поэтому известны не чтобы быть "действительно случайным". Любой такой алгоритмический подход будет иметь «период» - в конце концов он начнет повторяться.
Модуль Python random
использует особенно хороший и хорошо изученный псевдослучайный генератор, Mersenne Twister , с периодом 2**19937-1
- число, которое имеет более 6 тысяч цифр, когда записано в десятичных цифрах, как подтвердит len(str(2**19937-1))
;-). На моем ноутбуке я могу генерировать около 5 миллионов таких чисел в секунду:
$ python -mtimeit -s'import random' 'random.random()'
1000000 loops, best of 3: 0.214 usec per loop
Если предположить, что намного более быстрая машина способна генерировать млрд. таких чисел в секунду, цикл будет повторяться примерно за 10 5985 лет, и наилучшая текущая оценка для возраст Вселенной чуть меньше 1,5 * 10 12 лет. Таким образом, потребуется почти невообразимое количество жизней Вселенной, чтобы достичь точки повторения ;-). Параллельное вычисление не очень поможет; По оценкам, во Вселенной примерно 10 80 атомов, поэтому даже если бы вы смогли запустить такой генератор с миллиардом в секунду на каждом атоме во Вселенной, это все равно потребовало бы более 10 5800 Время жизни вселенной, чтобы начать повторяться.
Итак, вы могли бы оправдаться, подозревая, что это беспокойство по поводу повторения является чуть-чуть теоретическим, а не практическим вопросом; -).
Тем не менее, факториалы (которые учитывают перестановки последовательности длины N) также растут довольно быстро. Twister Mersenne, например, может быть в состоянии произвести все перестановки последовательности длиной 2080, но определенно не одной длины 2081 или выше. Если бы не проблема «времени жизни Вселенной», беспокойство докторов о «даже довольно малом len (x)» было бы оправданным - мы знаем , что многие возможные перестановки никогда не могут быть достигнуты путём перетасовки с таким псевдо-RNG, как только мы получим достаточно длинную последовательность, так что можно было бы беспокоиться о том, какой уклон мы фактически вводим даже с несколькими шаффлами !: -)
os.urandom обеспечивает доступ к любым источникам физических случайностей, которые предоставляет ОС - CryptGenRandom в Windows, / dev / urandom в Linux и т. д. 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)
и меньше беспокоиться о предвзятости; -).
К сожалению, измерения показывают, что этот подход к ГСЧ примерно в 50 раз медленнее, чем вызовы random.random()
- это может быть важным практическим соображением, если нам понадобится много случайных чисел (а если нет, беспокойство о возможной предвзятости может быть неуместным ;-). Подход os.urandom
также трудно использовать предсказуемым, повторяемым образом (например, для целей тестирования), в то время как для random.random()
вам нужно только указать фиксированный начальный random.seed
в начале теста, чтобы гарантировать воспроизводимое поведение.
Таким образом, на практике os.urandom
используется только тогда, когда вам нужны случайные числа «криптографического качества», которые не может предсказать решительный злоумышленник, и поэтому готовы заплатить практическую цену за использование вместо random.random
.