Ефективно генерувати 16-значний буквено-цифровий рядок


84

Я шукаю дуже швидкий спосіб генерування буквено-цифрового унікального ідентифікатора первинного ключа в таблиці.

Щось на зразок цієї роботи?

def genKey():
    hash = hashlib.md5(RANDOM_NUMBER).digest().encode("base64")
    alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", hash)
    return alnum_hash[:16]

Що було б хорошим способом генерації випадкових чисел? Якщо я базую це на мікрочасі, мені доводиться враховувати можливість декількох викликів genKey () одночасно з різних інстанцій.

Або є кращий спосіб зробити все це?


Відповіді:


116

Оскільки жодна з відповідей не надає вам випадкового рядка, що складається з символів 0-9, az, AZ: Ось робоче рішення, яке дасть вам один із прибл. 62 ^ 16 = 4.76724 e + 28 клавіш:

import random, string
x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16))
print(x)

Це також дуже читабельно, не знаючи напам'ять коди ASCII.

Існує ще коротша версія, оскільки python 3.6.2:

import random, string
x = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
print(x)

1
Номер насправді помилився. Я оновив його. Він обчислюється шляхом прийняття кількості можливих символів до ступеня довжини рядка.
Девід Шуман,

1
Дякуємо, що згадали random.choices. Не чув про це, і це значно швидше, ніж цикл на вибір
Ендрю

1
Дякую тобі за це.
Р. Карлус

49

Ви можете використовувати це:

>>> import random
>>> ''.join(random.choice('0123456789ABCDEF') for i in range(16))
'E2C6B2E19E4A7777'

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


1
random - це не випадково, а псевдовипадково згідно з документацією. Будь ласка, використовуйте замість цього os.urandom.
nikola

7
@prometheus. os.urandomне є psuedo-випадковим?
aaronasterling

1
Я відповідав на те, що Марк Байерс вільно вживав термін "випадкові значення". os.urandomвсе ще є псевдовипадковим, але криптографічно захищеним псевдовипадковим, що робить його набагато більш придатним для широкого кола випадків використання порівняно з random.
nikola

1
@nikola це не має значення, якщо ключі лише псевдовипадкові, вони використовуються для індексації.
ямм

3
Можливо, очевидно, але «детермінованість» не означає унікальність, ви повинні фактично перевірити, чи має алгоритм дуже довгий період повторення. get_key = lambda n: n % 10є детермінованим, але не унікальним надовго.
Марк

37

Погляньте на модуль uuid (Python 2.5+).

Швидкий приклад:

>>> import uuid
>>> uid = uuid.uuid4()
>>> uid.hex
'df008b2e24f947b1b873c94d8a3f2201'

Зверніть увагу, що OP запитував 16-значний буквено-цифровий рядок, але рядки UUID4 мають 32 символи. Не слід усікати цей рядок, замість цього використовуйте повні 32 символи.


7
Це 32 символи, а скорочення напрямних небезпечно.
Брайан

Правда (про усічення). З іншого боку: я б просто зберігав 32 символи (якщо у вас немає дуже конкретної причини зберігати лише 16 символів).
ChristopheD

1
@Brian Привіт, я повинен знати, чому настанови не безпечні? у вас є посилання?
Адіят Мубарак

1
@AdiyatMubarak: По суті, вам не потрібна довідка. Посібники задокументовані як унікальні. Половина керівництва не задокументована як унікальна. Тим не менш, blogs.msdn.microsoft.com/oldnewthing/20080627-00/?p=21823 проходить через те, що відбувається, коли ви скорочуєте один конкретний алгоритм GUID.
Брайан

22

У Python 3.6, випущений в грудні 2016 року, secretsмодуль був представлений.

Тепер ви можете генерувати випадковий маркер таким чином:

import secrets

secrets.token_hex(16)

З документів Python:

secretsМодуль використовується для генерації криптографически сильних випадкових чисел , придатних для управління даними , такі як паролі, аутентифікації облікового запису, маркери безпеки і пов'язаних з ними секретами.

Зокрема, secretsслід використовувати перевагу генератору псевдовипадкових чисел за замовчуванням у randomмодулі, який призначений для моделювання та моделювання, а не безпеки або криптографії.

https://docs.python.org/3/library/secrets.html


7

Для випадкових чисел хорошим джерелом є os.urandom:

 >> import os
 >> import hashlib
 >> random_data = os.urandom(128)
 >> hashlib.md5(random_data).hexdigest()[:16]

Я забув настільки чудову функцію urandom: V, і це приємно, краще, ніж додавати символи в рядок, а потім цикл. Builtin;)
m3nda

1
про це також згадувалося в інших відповідях, не слід скорочувати хеш md5.
bman

@bman: Я усвідомлюю, що є серйозні проблеми з усіченням вертенівських UUID, оскільки випадковість не розподілена лінійно. перед MD5 це не повинно бути проблемою.
максимум

3
>>> import random
>>> ''.join(random.sample(map(chr, range(48, 57) + range(65, 90) + range(97, 122)), 16))
'CDh0geq3NpKtcXfP'

4
Ваше рішення не включатиме символи 9, Z та z. Крім того, sample () вибирає кожного символа лише один раз. Отже, це дасть вам набагато менше перестановок. Це дасть вам рядок з 16 випадкових цифр та великі / малі літери:''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(6666))
Девід Шуман,

2

Це значення збільшується на 1 при кожному виклику (воно обертається). Вибір місця, де найкраще зберігати значення, залежатиме від того, як ви його використовуєте. Ви можете знайти це пояснення, яке цікавить, оскільки воно обговорює не тільки те, як працюють Посібники, але і як зробити менший.

Коротка відповідь така: Використовуйте деякі з цих символів як позначку часу, а інші символи як "уніфікатор", значення збільшується на 1 при кожному виклику вашого генератора uid.


-2

Просто використовуйте python вбудований uuid:

Якщо UUID добре для ваших цілей, використовуйте вбудований uuid пакет .

Однорядкове рішення:

>>> import uuid
>>> str(uuid.uuid4().get_hex().upper()[0:16])
'40003A9B8C3045CA'

6
UUID має довжину 32 символи, використовуючи лише символи від 0 до 15, ви отримаєте дублікати.
Diaa Mohamed Kasem



-3

Ви можете використовувати функцію вибору в np.random, яка вибирає кількість символів, вказану зі списку символів:

import numpy as np
chars = np.array(list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'))
np_codes = np.random.choice(chars,16)
print(''.join([val for val in np_codes]))

це виводить щось на зразок наступного: 591FXwW61F4Q57av

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.