PyMOTW: uuid

4 Agosto 2008

Traducción de PyMOTW: uuid el módulo uuid de la columna semanal de Doug Hellmann.


Comentarios

El módulo uuid implementa Identificadores Universalmente Únicos (Universally Unique Identifiers) como se describen en el RFC 4122.

Módulo: uuid
Propósito: Generar identificadores únicos para objetos.
Versión de Python: 2.5

Descripción:

RFC 4122 define un sistema para crear identificadores universalmente únicos para recursos de una manera que no requiere un registro central. Valores UUID son de 128 bits y "pueden garantizar singularidad a través del espacio y el tiempo". Son útiles para identificadores de documentos, hosts, clientes de aplicaciones y otras situaciones donde un valor único es necesario. El RFC está orientada específicamente a crear un espacio de nombres uniformes de recursos (Uniform Resource Name namespace).

Tres algoritmos principales son descritos en la especificación:

En todos los casos, el valor semilla se combina con el reloj del sistema y un valor de secuencia del reloj (para mantener singularidad en caso que el reloj haya sido retrasado).

UUID 1 - Dirección MAC IEEE 802:

Valores UUID versión 1 se calculan usando la dirección MAC del host. El módulo uuidusa getnode() para extraer el valor MAC en un sistema:

import uuid

print hex(uuid.getnode())

$ python uuid_getnode.py
0x13a94e3959L

Si un sistema tiene más de una tarjeta de red, y por tanto más de una MAC, cualquiera de los valores puede ser el resultado.

Para generar el UUID de una tarjeta de red dada, identificada por su dirección MAC, usa la función uuid1(). Puedes pasarle un identificador de nodo o dejar el campo vacío para usar el valor devuelto por getnode().

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 '\ttime_low            : ', u.time_low
print '\ttime_mid            : ', u.time_mid
print '\ttime_hi_version     : ', u.time_hi_version
print '\tclock_seq_hi_variant: ', u.clock_seq_hi_variant
print '\tclock_seq_low       : ', u.clock_seq_low
print '\tnode                : ', u.node
print '\ttime                : ', u.time
print '\tclock_seq           : ', u.clock_seq

Los componentes del objeto UUID devuelto son accesible a través de atributos de instancia sólo de lectura. Algunos atributos, como hex, int y urn, son representaciones distintas del valor UUID.

$ python uuid_uuid1.py
56a638a0-6298-11dd-9170-0013a94e3959
<class 'uuid.UUID'>
bytes   : 'V\xa68\xa0b\x98\x11\xdd\x91p\x00\x13\xa9N9Y'
hex     : 56a638a0629811dd91700013a94e3959
int     : 115176677437976725286414991448563661145
urn     : urn:uuid:56a638a0-6298-11dd-9170-0013a94e3959
variant : specified in RFC 4122
version : 1
fields  : (1453734048L, 25240L, 4573L, 145L, 112L, 84444854617L)
        time_low            :  1453734048
        time_mid            :  25240
        time_hi_version     :  4573
        clock_seq_hi_variant:  145
        clock_seq_low       :  112
        node                :  84444854617
        time                :  134371970319268000
        clock_seq           :  4464

Debido al componente time, cada vez que se invoca uuid1() un nuevo valor es devuelto.

import uuid

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

Nota en este resultado que solamente el componente de tiempo (al inicio de la cadena) cambia.

$ python uuid_uuid1_repeat.py
a9a0122e-6298-11dd-a0e0-0013a94e3959
a9a01846-6298-11dd-a0e0-0013a94e3959
a9a01a80-6298-11dd-a0e0-0013a94e3959

Por supuesto, ya que tu computadora tiene una dirección MAC distinta a la mía, verás valores enteramente distintos si ejecutas los ejemplos, porque e identificador de nodo al final del UUID cambiará también.

import uuid

node1 = uuid.getnode()
print hex(node1), uuid.uuid1(node1)

node2 =  0x1e5274040e
print hex(node2), uuid.uuid1(node2)

$ python uuid_uuid1_othermac.py
0x13a94e3959L f7ab00fa-6298-11dd-8593-0013a94e3959
0x1e5274040eL f7ab05a8-6298-11dd-b475-001e5274040e

UUID 3 y 5 - Valores basados en nombres:

Es también útil en ciertos contextos el crear valores UUID a partir de nombres en lugar de valores al azar o basados en el tiempo Las versiones 3 y 5 de la especificación UUID utilizan sumas criptográficas (MD5 o SHA-1) para combinar valores semilla específicos con "nombres" (nombres DNS, URLs, identificadores de objetos, etc.). Hay muchos espacios de nombres conocidos, identificados por valores UUID pre definidos, para trabajar con DNS, URLs, OIDs de ISO y nombres distinguidos (distinguished names) de X.500. Puedes también definir tu propio espacio de nombres específico a una aplicación generando y guardando valores UUID.

Para crear un UUID desde un nombre DNS, pasa uuid.NAMESPACE_DNS como el argumento del espacio de nombres del nombre a uuid3() o uuid5():

import uuid

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

for name in hostnames:
    print name
    print '\tMD5   :', uuid.uuid3(uuid.NAMESPACE_DNS, name)
    print '\tSHA-1 :', uuid.uuid5(uuid.NAMESPACE_DNS, name)

$ python 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

El valor UUID para el mismo nombre es siempre el mismo, sin importar cuándo o dónde es calculado. Valores para el mismo nombre en distintos espacios de nombres son distintos por supuesto.

import uuid

for i in xrange(3):
    print uuid.uuid3(uuid.NAMESPACE_DNS, 'www.doughellmann.com')

$ python uuid_uuid3_repeat.py
bcd02e22-68f0-3046-a512-327cca9def8f
bcd02e22-68f0-3046-a512-327cca9def8f
bcd02e22-68f0-3046-a512-327cca9def8f

UUID 4 - Valores al azar:

A veces, valores UUID basados en host o espacios de nombres no son "suficientemente distintos". E casos donde quieres usar el UUID como una llave de búsqueda, una secuencia más al azar con más diferenciación es deseable. Es estas situaciones, usa uuid4() para generar UUIDs desde valores al azar.

import uuid

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

$ python uuid_uuid4.py
bff4da9f-c7f2-4b1a-a456-4a3e50102dec
7e894f08-e970-456d-8743-e53680adfd7c
b25e24f1-9382-4e68-b820-228c02aae263

Trabajando con objetos UUID:

Además de generar nuevos valores UUID, puedes analizar cadenas en varios formatos para crear objetos UUID. Ésto hace más fácil el compararlos, ordenarlos, etc.

import uuid

def show(msg, l):
    print msg
    for v in l:
        print '\t', 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('convertidos en uuids', uuids)

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

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

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

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

Referencias:

RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace
Python Module of the Week Home
Descarga el código

Copyright 2008 Doug Hellmann


blog comments powered by Disqus

Categorías