2015-09-01 5 views
4

Я ищу способ генерации случайной строки из n байтов в Python аналогично методу os.urandom(), за исключением предоставления способа генерации данных.Генерация случайной строки семенных данных

До сих пор у меня есть:

def genRandData(size): 
    buf = chr(random.randint(0,255)) 
    for i in range(size-1): 
     buf = buf + chr(random.randint(0,255)) 
    return str(buf) 

Однако эта функция очень медленно, генерируя мегабайта данных занимает около 1,8 секунды на моей машине. Есть ли способ улучшить это (или, альтернативно, способ семени os.urandom).

+0

FWIW, 'urandom' получает свою случайность от случайного системного шума (см. [Справочная страница Linux для urandom] (http://linux.die.net/man/4/urandom)), поэтому он не делает чтобы дать возможность посева. Отсутствие посева является раздражающим для тестирования вещей, но OTOH делает его полезным источником случайности для криптографических целей. Я думаю, это не имеет особого отношения к вашему вопросу, но, по крайней мере, это объясняет, почему нет возможности его посеять. :) –

ответ

1

НОВЫЙ ОТВЕТ

После перечитывания вопрос OP, я теперь понимаю, что речь идет о необработанных байтов, а не ASCII символы строковые

Итак, как об этом?

import random 
gl = 0 
def randBytes(size): 
    global gl 
    nr = bytearray(random.getrandbits(8) for _ in xrange(size)) 
    gl = nr 
    return 

%timeit randBytes(1000000) 
1 loops, best of 3: 262 ms per loop 

In [27]: gl.__sizeof__() 
Out[27]: 1087223 

OLD ОТВЕТ ЗДЕСЬ

import random 
import string 
def generateRandomString(size): 
    return(''.join(random.choice(string.ascii_letters) for i in range(size))) 

Примечания:

Один ASCII символ 1 байт. Таким образом, «размер» обозначает длину строки и размер в байтах.

Вы можете использовать string.ascii_uppercase или ascii_lowercase иметь либо нижний и верхний регистр

random.seed может быть использован для определения семян.

random.seed ([х]) ¶

Инициализировать основной генератор случайных чисел. Необязательный аргумент x может быть любым хешируемым объектом. Если x опущен или None, используется текущее системное время ; текущее системное время также используется для инициализации генератора , когда модуль сначала импортируется. Если источники случайности предоставлены операционной системой , они используются вместо системного времени (см. функция os.urandom() для получения подробной информации о доступности).

Таким образом, вы могли бы:

import random 
    import string 
    def generateRandomString(size, seed=None): 
     if seed != None: 
      random.seed(seed) 
     return(''.join(random.choice(string.ascii_letters) for i in range(size))) 

Тайминги:

In [30]: %time generateRandomString(1000000) 
Wall time: 554 ms 
<and then output> 
+0

1) OP хочет все возможные байтовые значения от '\ x00' до' \ xff', а не только букв. 2) Более эффективно использовать '.join()' для понимания списка, чем для выражения генератора, поскольку '.join()' должен проверять строки, которые он соединяет дважды: в первый раз, чтобы определить общую длину, второй время для копирования строк в буфер назначения. Подробнее см. [Этот ответ] (http://stackoverflow.com/a/9061024/4014959) разработчиком ядра Python Раймондом Хеттингером. –

+0

Хм, справа. Не читал это правильно. Просто дал новый ответ! – cristianmtr

+0

Ничего себе, использование 'getrandbits' определенно быстрее моего решения. Но почему вы делаете это с глобалами? –

3

Если у вас есть numpy доступны, он имеет версию random модуля как numpy.random, который содержит эту функцию, вы могли бы рассмотреть:

numpy.random.bytes(length) 

Это очень быстро:

$ python -mtimeit "import numpy" "numpy.random.bytes(1<<30)" 
10 loops, best of 3: 2.19 sec per loop 

Это для 1GiB.

И вы можете засеять его numpy.random.seed.

0

Как говорит Дэн Д., давая numpy генерировать ваши байты одним ударом со скоростью C, это будет способ быстрее, чем производить их по одному на скорости Python.

Однако, если вы не хотите использовать numpy, вы можете сделать свой код немного более эффективным.

Построение строки путем конкатенации, например, buf = buf + chr(random.randint(0,255)) происходит очень медленно, так как новый buf должен быть выделен на каждом цикле (помните, что строки Python неизменяемы). Обычная техника в Python для построения строки из подстрок состоит в том, чтобы скопировать подстроки в списке, а затем использовать метод str.join(), чтобы объединить их за один раз.

Мы также можем сэкономить немного времени, предварительно создавая список наших 1-байтовых строк, вместо того, чтобы звонить chr() за каждый байт, который мы хотим.

from random import seed, choice 

allbytes = [chr(i) for i in range(256)] 

def random_bytes(n): 
    bytes = [] 
    for _ in range(n): 
     bytes.append(choice(allbytes)) 
    return ''.join(bytes) 

Мы можем упростить это и сделать его слегка более эффективным, используя список понимание:

def random_bytes(n): 
    return ''.join([choice(allbytes) for _ in range(n)]) 

В зависимости от того, как вы собираетесь использовать эти случайные байты, вы можете найти его полезно поместить их в объект bytearray или bytes.

Вот вариант на основе нового ответа cristianmtr в:

def random_bytes(n): 
    return bytes(bytearray(getrandbits(8) for _ in xrange(n))) 

Вы могли использовать str() вместо bytes(), но bytes() лучше для Python 3, поскольку Python 3 строки Unicode.

Смежные вопросы