Випадкові рядки в Python 2.6 (Це нормально?)


77

Я намагався знайти більш пітонічний спосіб генерації випадкового рядка в python, який також може масштабуватися. Як правило, я бачу щось подібне до

''.join(random.choice(string.letters) for i in xrange(len))

Це відмовно, якщо ви хочете створити довгий рядок.

Я деякий час думав про random.getrandombits і з'ясував, як перетворити це на масив бітів, а потім шістнадцяткове кодування. Використовуючи python 2.6, я натрапив на об’єкт bitarray, який не задокументований. Якось я змусив це працювати, і це здається дуже швидко.

Він генерує 50-міліметровий випадковий рядок на моєму ноутбуці приблизно за 3 секунди.

def rand1(leng):
    nbits = leng * 6 + 1
    bits = random.getrandbits(nbits)
    uc = u"%0x" % bits
    newlen = int(len(uc) / 2) * 2 # we have to make the string an even length
    ba = bytearray.fromhex(uc[:newlen])
    return base64.urlsafe_b64encode(str(ba))[:leng]

редагувати

heikogerlach зазначив, що причиною проблеми стала непарна кількість символів. Новий код додано, щоб переконатися, що він завжди надсилав із шістнадцяткового числа парну кількість шістнадцяткових цифр.

Досі цікаво, чи є кращий спосіб зробити це так само швидко.


1
Як зробити це так, щоб воно містило лише цифри, літери та підкреслення? (Сюди входить і тире)
Венберт

2
@wenbert '' .join (random.choice (string.letters + string.digits + "_") for i in xrange (length))
yanjost

Відповіді:


130
import os
random_string = os.urandom(string_length)

і якщо вам потрібна URL-адреса безпечного рядка:

import os
random_string = os.urandom(string_length).hex() 

(зауважте, довжина random_string у цьому випадку найбільша за довжину string_length)


9
Це, мабуть, тому, що os.urandom буде криптографічно захищеним PRNG (зазвичай це потоковий шифр), тоді як random - це «звичайний» PRNG, який, як правило, набагато швидший для обчислення.
Джої,

6
Чи є спосіб використовувати це для створення рядків ASCII, а не Unicode? Наприклад, тому рядок може використовуватися в URL-адресі.
Дерек Дамер

8
Ви можете використовувати random.choice, string.digits і string.letters, як перший приклад: >>> імпортувати random, string >>> '' .join (random.choice (string.letters + string.digits) for i in xrange (10)) 'FywhcRLmh1' (я припускаю, що ви не генеруєте величезний рядок, подібний до операційного, оскільки це для URL-адреси ...)
JJ Geewax,

63
Зокрема, я використав це: base64.urlsafe_b64encode (os.urandom (30))
jricher

4
Вибачте за повторну публікацію у старому ланцюжку. Чи є спосіб використовувати os.urandom(string_length)та отримати лише листи ASCII? ... Оскільки python - це інтерпретована мова, цикл, який генерує по одному байту, здається досить дорогим.
BiGYaN

10

Іноді uuid досить короткий, і якщо вам не подобаються тире, ви завжди можете. Замінити ('-', '') їх

from uuid import uuid4

random_string = str(uuid4())

Якщо вам потрібна конкретна довжина без тире

random_string_length = 16
str(uuid4()).replace('-', '')[:random_string_length]

або використовуйте uuid4().hexдля отримання значення без дефісів
davoclavo

6

Взято зі звіту про помилки 1023290 на Python.org:

junk_len = 1024
junk =  (("%%0%dX" % junk_len) % random.getrandbits(junk_len *
8)).decode("hex")

Крім того , побачити проблеми 923643 і 1023290


2

Здається, fromhex()метод передбачає парну кількість шістнадцяткових цифр. Ваш рядок має 75 символів. Майте на увазі, що something[:-1] виключає останній елемент! Просто використовуйте something[:].


Був кінцевий L із __hex __ (). Я переписав зразок коду. У будь-якому випадку, я думаю, ви мали рацію, коли це вимагало
парну

2

Щодо останнього прикладу, наступне виправлення, щоб переконатися, що рядок рівномірний, незалежно від значення junk_len:

junk_len = 1024
junk =  (("%%0%dX" % (junk_len * 2)) % random.getrandbits(junk_len * 8)).decode("hex")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.