Случайные строки в Python 2.6 (это нормально?)

Asked
Viewd44479

77

Я пытался найти более питонический способ создания случайной строки в Python, который также может масштабироваться. Обычно я вижу что-то похожее на

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

Отстой, если вы хотите создать длинную строку.

Некоторое время я думал о random.getrandombits и придумывал, как преобразовать это в массив бит, а затем закодировать его в шестнадцатеричном формате. Используя python 2.6, я наткнулся на объект битового массива, который не задокументирован. Каким-то образом я заставил его работать, и это кажется очень быстрым.

Он генерирует случайную строку размером 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]
 

Хайкогерлах указал, что причиной проблемы было нечетное количество символов. Добавлен новый код, чтобы он всегда отправлял из шестнадцатеричного числа четное число шестнадцатеричных цифр.

Мне все еще интересно, есть ли лучший способ сделать это так же быстро.

5 ответов

130
 import os
random_string = os.urandom(string_length)
 

и если вам нужна безопасная строка для URL:

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

(обратите внимание, что в этом случае длина random_string больше, чем string_length)

  • А! Так просто. Я не думал, что это кроссплатформенный, но, похоже, это так.

    mikelikespie24 апреля 2009, 09:17
  • Есть ли способ использовать это для генерации строк ASCII, а не Unicode? Например, строка может использоваться в URL.

    Derek Dahmer06 февраля 2010, 02:07
  • Вы можете использовать random.choice, string.digits и string.letters, как в первом примере: »> Импортировать случайный, строка »>‘ ‘.Join (random.choice (string.letters + string.digits) для i в xrange (10)) ‘FywhcRLmh1’

    (Полагаю, вы не генерируете огромную строку, такую ​​как op, поскольку она предназначена для URL…)

    JJ Geewax19 марта 2010, 18:45
  • Вероятно, это связано с тем, что os.urandom будет криптографически безопасным ГПСЧ (обычно это потоковый шифр), в то время как random - это «нормальный» ГПСЧ, который обычно вычисляется намного быстрее.

    Joey24 апреля 2009, 12:29
  • Просто продолжение, это действительно странно, но, по крайней мере, в OS X метод getrandbits работает в 2–3 раза быстрее.

    mikelikespie24 апреля 2009, 09:25
  • Для URL-адресов можно использовать string.ascii_letters.

    jholster22 мая 2010, 16:21
2

Что касается последнего примера, следующее исправление, обеспечивающее одинаковую длину строки, независимо от значения junk_len:

 junk_len = 1024
junk =  (("%%0%dX" % (junk_len * 2)) % random.getrandbits(junk_len * 8)).decode("hex")
 
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 было шестнадцатеричное (). Я переписал пример кода. В любом случае, я думаю, вы были правы, требуя четного числа цифр

    mikelikespie24 апреля 2009, 09:17