Рубрики
Без рубрики

uuid – универсальные уникальные идентификаторы

Автор оригинала: Doug Hellmann.

Цель:

В

uuid

модуль реализует универсальные уникальные идентификаторы, как описано в RFC 4122.

RFC 4122 определяет систему для создания универсальных уникальных идентификаторов для ресурсов таким образом, чтобы не требуется центральный регистратор. Значения UUID имеют длину 128 бит и, как сказано в справочнике, «могут гарантировать уникальность в пространстве и времени». Они полезны для генерации идентификаторов для документов, хостов, клиентов приложений и других ситуаций, когда необходимо уникальное значение. RFC специально ориентирован на создание пространства имен Uniform Resource Name и охватывает три основных алгоритма:

  • Использование MAC-адресов IEEE 802 как источника уникальности
  • Использование псевдослучайных чисел
  • Использование хорошо известных строк в сочетании с криптографическим хешированием

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

UUID 1 – MAC-адрес IEEE 802

Значения UUID версии 1 вычисляются с использованием MAC-адреса хоста. Модуль uuid использует getnode () для получения значения MAC текущей системы.

uuid_getnode.py

import uuid

print(hex(uuid.getnode()))

Если в системе более одной сетевой карты и, следовательно, более одного MAC, может быть возвращено любое из значений.

$ python3 uuid_getnode.py

0xa860b60304d5

Чтобы сгенерировать UUID для хоста, идентифицируемого по его MAC-адресу, используйте функцию uuid1 () . Аргумент идентификатора узла не является обязательным; оставьте поле пустым, чтобы использовать значение, возвращаемое getnode () .

uuid_uuid1.py

import uuid

u  uuid.uuid1()

print(u)
print(type(u))
print('bytes   :', repr(u.bytes))
print('hex     :', u.hex)
print('int     :', u.int)
print('urn     :', u.urn)
print('variant :', u.variant)
print('version :', u.version)
print('fields  :', u.fields)
print('  time_low            : ', u.time_low)
print('  time_mid            : ', u.time_mid)
print('  time_hi_version     : ', u.time_hi_version)
print('  clock_seq_hi_variant: ', u.clock_seq_hi_variant)
print('  clock_seq_low       : ', u.clock_seq_low)
print('  node                : ', u.node)
print('  time                : ', u.time)
print('  clock_seq           : ', u.clock_seq)

К компонентам возвращенного объекта UUID можно получить доступ через атрибуты экземпляра только для чтения. Некоторые атрибуты, такие как hex , int и urn , представляют собой разные представления значения UUID.

$ python3 uuid_uuid1.py

38332b62-2aea-11e8-b103-a860b60304d5

bytes   : b'83+b*\xea\x11\xe8\xb1\x03\xa8`\xb6\x03\x04\xd5'
hex     : 38332b622aea11e8b103a860b60304d5
int     : 74702454824994792138317938288475964629
urn     : urn:uuid:38332b62-2aea-11e8-b103-a860b60304d5
variant : specified in RFC 4122
version : 1
fields  : (942877538, 10986, 4584, 177, 3, 185133323977941)
  time_low            :  942877538
  time_mid            :  10986
  time_hi_version     :  4584
  clock_seq_hi_variant:  177
  clock_seq_low       :  3
  node                :  185133323977941
  time                :  137406974088391522
  clock_seq           :  12547

Из-за компонента времени каждый вызов uuid1 () возвращает новое значение.

uuid_uuid1_repeat.py

import uuid

for i in range(3):
    print(uuid.uuid1())

В этом выводе изменяется только компонент времени (в начале строки).

$ python3 uuid_uuid1_repeat.py

3842ca28-2aea-11e8-8fec-a860b60304d5
3844cd18-2aea-11e8-aca3-a860b60304d5
3844cdf4-2aea-11e8-ac38-a860b60304d5

Поскольку каждый компьютер имеет свой MAC-адрес, запуск программы-примера в разных системах даст совершенно разные значения. В этом примере передаются явные идентификаторы узлов для имитации работы на разных хостах.

uuid_uuid1_othermac.py

import uuid

for node in [0x1ec200d9e0, 0x1e5274040e]:
    print(uuid.uuid1(node), hex(node))

В дополнение к другому значению времени также изменяется идентификатор узла в конце UUID.

$ python3 uuid_uuid1_othermac.py

3851ea50-2aea-11e8-936d-001ec200d9e0 0x1ec200d9e0
3852caa6-2aea-11e8-a805-001e5274040e 0x1e5274040e

UUID 3 и 5 – значения на основе имени

В некоторых контекстах также полезно создавать значения UUID из имен вместо случайных или основанных на времени значений. Версии 3 и 5 спецификации UUID используют криптографические хеш-значения (MD5 или SHA-1, соответственно) для объединения начальных значений, зависящих от пространства имен, с именами. Существует несколько хорошо известных пространств имен, определяемых заранее заданными значениями UUID, для работы с DNS, URL-адресами, ISO OID и отличительными именами X.500. Новые пространства имен для конкретных приложений могут быть определены путем создания и сохранения значений UUID.

uuid_uuid3_uuid5.py

import uuid

hostnames  ['www.doughellmann.com', 'blog.doughellmann.com']

for name in hostnames:
    print(name)
    print('  MD5   :', uuid.uuid3(uuid.NAMESPACE_DNS, name))
    print('  SHA-1 :', uuid.uuid5(uuid.NAMESPACE_DNS, name))
    print()

Чтобы создать UUID из имени DNS, передайте uuid.NAMESPACE_DNS в качестве аргумента пространства имен в uuid3 () или uuid5 () :

$ python3 uuid_uuid3_uuid5.py

www.doughellmann.com
  MD5   : bcd02e22-68f0-3046-a512-327cca9def8f
  SHA-1 : e3329b12-30b7-57c4-8117-c2cd34a87ce9

blog.doughellmann.com
  MD5   : 9bdabfce-dfd6-37ab-8a3f-7f7293bcf111
  SHA-1 : fa829736-7ef8-5239-9906-b4775a5abacb

Значение UUID для данного имени в пространстве имен всегда одно и то же, независимо от того, когда и где оно вычислено.

uuid_uuid3_repeat.py

import uuid

namespace_types  sorted(
    n
    for n in dir(uuid)
    if n.startswith('NAMESPACE_')
)
name  'www.doughellmann.com'

for namespace_type in namespace_types:
    print(namespace_type)
    namespace_uuid  getattr(uuid, namespace_type)
    print(' ', uuid.uuid3(namespace_uuid, name))
    print(' ', uuid.uuid3(namespace_uuid, name))
    print()

Значения для одного и того же имени в пространствах имен различаются.

$ python3 uuid_uuid3_repeat.py

NAMESPACE_DNS
  bcd02e22-68f0-3046-a512-327cca9def8f
  bcd02e22-68f0-3046-a512-327cca9def8f

NAMESPACE_OID
  e7043ac1-4382-3c45-8271-d5c083e41723
  e7043ac1-4382-3c45-8271-d5c083e41723

NAMESPACE_URL
  5d0fdaa9-eafd-365e-b4d7-652500dd1208
  5d0fdaa9-eafd-365e-b4d7-652500dd1208

NAMESPACE_X500
  4a54d6e7-ce68-37fb-b0ba-09acc87cabb7
  4a54d6e7-ce68-37fb-b0ba-09acc87cabb7

UUID 4 – случайные значения

Иногда значения UUID на основе хоста и пространства имен недостаточно различаются. Например, в случаях, когда UUID предназначен для использования в качестве хеш-ключа, желательна более случайная последовательность значений с большей дифференциацией, чтобы избежать коллизий в хеш-таблице. Наличие значений с меньшим количеством общих цифр также упрощает их поиск в файлах журнала. Чтобы добавить большую дифференциацию в UUID, используйте uuid4 () для их генерации с использованием случайных входных значений.

uuid_uuid4.py

import uuid

for i in range(3):
    print(uuid.uuid4())

Источник случайности зависит от того, какие библиотеки C доступны при импорте uuid . Если libuuid (или uuid.dll ) может быть загружен и он содержит функцию для генерации случайных значений, он используется. В противном случае используются os.urandom () или модуль random.

$ python3 uuid_uuid4.py

74695723-65ed-4170-af77-b9f22608535d
db199e25-e292-41cd-b488-80a8f99d163a
196750b3-bbb9-488e-b3ec-62ec0e468bbc

Работа с объектами UUID

Помимо создания новых значений UUID, можно анализировать строки в стандартных форматах для создания объектов UUID, что упрощает обработку операций сравнения и сортировки.

uuid_uuid_objects.py

import uuid


def show(msg, l):
    print(msg)
    for v in l:
        print(' ', v)
    print()


input_values  [
    'urn:uuid:f2f84497-b3bf-493a-bba9-7c68e6def80b',
    '{417a5ebb-01f7-4ed5-aeac-3d56cd5037b0}',
    '2115773a-5bf1-11dd-ab48-001ec200d9e0',
]

show('input_values', input_values)

uuids  [uuid.UUID(s) for s in input_values]
show('converted to uuids', uuids)

uuids.sort()
show('sorted', uuids)

Окружающие фигурные скобки удаляются из ввода, как и тире ( - ). Если в строке есть префикс, содержащий urn: и/или uuid: , он также удаляется. Остающийся текст должен быть строкой из 16 шестнадцатеричных цифр, которые затем интерпретируются как значение UUID.

$ python3 uuid_uuid_objects.py

input_values
  urn:uuid:f2f84497-b3bf-493a-bba9-7c68e6def80b
  {417a5ebb-01f7-4ed5-aeac-3d56cd5037b0}
  2115773a-5bf1-11dd-ab48-001ec200d9e0

converted to uuids
  f2f84497-b3bf-493a-bba9-7c68e6def80b
  417a5ebb-01f7-4ed5-aeac-3d56cd5037b0
  2115773a-5bf1-11dd-ab48-001ec200d9e0

sorted
  2115773a-5bf1-11dd-ab48-001ec200d9e0
  417a5ebb-01f7-4ed5-aeac-3d56cd5037b0
  f2f84497-b3bf-493a-bba9-7c68e6def80b

Смотрите также