uuid - Identificatori Universalmente Univoci
Scopo: Implementa gli Identificatori Universalmente Univoci (Universally Unique Identifiers) come descritti in RFC 4122
RFC 4122 definisce un sistema per creare Identificatori Universalmente Univoci (UUID) per risorse in modo che non richieda mantenerne traccia tramite la gestione di un archivio centralizzato. I valori UUID sono lunghi 128 bit e come recita la guida di riferimento, "possono garantire l'univocità attraverso lo spazio e il tempo". Sono utili per generare identificatori per documenti, host, applicazioni client, e altre situazioni nelle quali sia necessario un valore univoco. La RFC è in particolare orientata verso la creazione di uno spazio dei nomi chiamato "Uniform Resource Name" e copre tre algoritmi principali:
- Uso degli indirizzi IEEE 802 MAC come fonte di univocità
- Uso dei numeri pseudo-casuali
- Uso di stringhe note in combinazione con hashing crittografico
In tutti i casi il valore di origine viene combinato con il clock di sistema e una sequenza di valori di clock usati per mantenere univocità nel caso che il clock sia messo indietro.
UUID 1 - Indirizzi IEEE 802 MAC
Nella versione UUID 1 valori sono calcolati usando l'indirizzo MAC dell'host. Il modulo uuid usa getnode()
per recuperare il valore MAC del sistema corrente:
# uuid_getnode.py
import uuid
print(hex(uuid.getnode()))
Se un sistema ha più di una scheda di rete, quindi più di un MAC può essere ritornato uno qualsiasi dei valori.
$ python3 uuid_getnode.py 0xf46d0462e951
Per generare un UUID per un dato host, identificato dal suo indirizzo MAC, si usa la funzione uuid1()
. L'identificatore di nodo è opzionale, si lasci il campo vuoto per usare il valore restituito da 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)
I componenti dell'oggetto UUID restituito possono essere indirizzati tramite degli attributi di istanza a sola lettura. Alcuni attributi, come hex
, int
ed urn
sono diverse rappresentazioni del valore UUID.
$ python3 uuid_uuid1.py 0dca8244-f9f7-11e6-8f16-f46d0462e951 <class 'uuid.UUID'> bytes : b'\r\xca\x82D\xf9\xf7\x11\xe6\x8f\x16\xf4m\x04b\xe9Q' hex : 0dca8244f9f711e68f16f46d0462e951 int : 18331450088751923872094499947564689745 urn : urn:uuid:0dca8244-f9f7-11e6-8f16-f46d0462e951 variant : specified in RFC 4122 version : 1 fields : (231375428, 63991, 4582, 143, 22, 268749062203729) time_low : 231375428 time_mid : 63991 time_hi_version : 4582 clock_seq_hi_variant: 143 clock_seq_low : 22 node : 268749062203729 time : 137071678164992580 clock_seq : 3862
A causa della componente temporale, ogni chiamata ad uuid1()
restituisce un nuovo valore.
# uuid_uuid1_repeat.py
import uuid
for i in range(3):
print(uuid.uuid1())
Nell'output cambia solo la componente temporale (all'inizio della stringa).
$ python3 uuid_uuid1_repeat.py 65275ca6-f9f7-11e6-8f16-f46d0462e951 65275ca7-f9f7-11e6-8f16-f46d0462e951 65275ca8-f9f7-11e6-8f16-f46d0462e951
Visto ogni computer ha il proprio indirizzo MAC, quando si esegue il programma di esempio su sistemi differenti, i valori saranno completamente diversi. Questo esempio passa esplicitamente l'identificatore di nodo per simulare l'esecuzione su host differenti.
# uuid_uuid1_othermac.py
import uuid
for node in [0x1ec200d9e0, 0x1e5274040e]:
print(uuid.uuid1(node), hex(node))
Oltre a diversi valori temporali, cambia anche l'identificatore di nodo alla fine dell'UUID.
$ python3 uuid_uuid1_othermac.py ded265e8-f9f7-11e6-8e61-001ec200d9e0 0x1ec200d9e0 ded26912-f9f7-11e6-ada2-001e5274040e 0x1e5274040e
UUID 3 e 5 - Valori Basati sui Nomi
E' anche utile, in certi contesti, creare valori UUID da nomi invece che da valori casuali o basati sul tempo. Le versioni 3 e 5 delle specifiche UUID usano valori hash crittografici (MD5 oppure SHA-1) per combinare valori di origine specifici dello spazio dei nomi con "nomi". Ci sono diversi spazi dei nomi ben noti, identificati da valori UUID predefiniti, per lavorare con DNS, URL, ISO OID ed X.500 Distinguished Names. Si possono anche definire nuovi spazi dei nomi specifici per una applicazione generando e salvando i valori 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))
Per creare un UUID da un nome DNS, si passi uuid.NAMESPACE_DNS
come argomento namespace
per uuid3()
oppure 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
Il valore UUID per un dato nome in uno spazio dei nomi è sempre lo stesso, non importa quando o dove esso viene calcolato.
# 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()
I valori per lo stesso nome negli spazi dei nomi sono diversi.
$ 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 - Valori Casuali
Talvolta i valori UUID basati sull'host e sullo spazio dei nomi sono sono "diversi abbastanza". Ad esempio, in casi dove si voglia usare un UUID come chiave di hash, è desiderabile una sequenza di valori più casuale con più differenziazioni per evitare collisioni nella hash table. Il disporre di valori con meno cifre comuni rende inoltre più semplice trovarli nei file di registro. Per aggiungere una differenziazione maggiore nel proprio UUID, si usa uuid4()
per generare i valori usando dati in input casuali.
# uuid_uuid4.py
import uuid
for i in range(3):
print(uuid.uuid4())
La sorgente della casualità dipende da quali librerie C sono disponibili quando viene importato uuid
. Se libuuid
(oppure uuid.dll
) possono essere caricate e contengono una funzione per generare valori casuali, essa viene usata. Altrimenti viene usato os.urandom()
oppure il modulo random.
$ python3 uuid_uuid4.py 4a9122e8-dbd2-4706-bbab-6982073fe23e 2138606e-42bb-4f69-a325-b4595487a133 6a17d800-ba00-4691-9a36-f3be9e92b2fb
Lavorare con Oggetti UUID
Oltre a generare nuovi valori UUID, si possono anche elaborare stringhe in formati standard per creare oggetti UUID. Questo rende facile la gestione di operazioni di confronto e ordinamento.
# 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('valori in input', input_values)
uuids = [uuid.UUID(s) for s in input_values]
show('convertiti in uuid', uuids)
uuids.sort()
show('ordinati', uuids)
Le parentesi graffe vengono rimosse dall'input, così come i trattini (-). Se la stringa ha un prefisso che contiene urn:
e/o uuid:
viene anch'esso rimosso. Il testo rimanente deve essere una stringa di 16 cifre esadecimali, che saranno interpretate come valore UUID.
$ python3 uuid_uuid_objects.py valori in input urn:uuid:f2f84497-b3bf-493a-bba9-7c68e6def80b {417a5ebb-01f7-4ed5-aeac-3d56cd5037b0} 2115773a-5bf1-11dd-ab48-001ec200d9e0 convertiti in uuid f2f84497-b3bf-493a-bba9-7c68e6def80b 417a5ebb-01f7-4ed5-aeac-3d56cd5037b0 2115773a-5bf1-11dd-ab48-001ec200d9e0 ordinati 2115773a-5bf1-11dd-ab48-001ec200d9e0 417a5ebb-01f7-4ed5-aeac-3d56cd5037b0 f2f84497-b3bf-493a-bba9-7c68e6def80b
Vedere anche:
- uuid
- La documentazione della libreria standard per questo modulo
- Note di portabilità per uuid
- RFC 4122
- Uno spazio dei nomi URN per Universally Unique IDentifiers (UUID)