Python3標准庫:uuid 全局唯一標識符


1. uuid 全局唯一標識符

uuid 模塊實現了全局唯一標識符(Universally Unique Identifier);這個RFC定義了一個系統,可以為資源創建唯一的標識符,這里采用一種不需要集中注冊機的方式。UUID值為128位,正如參考指南所述,“UUID可以保證跨空間和時間的唯一性”。對於文檔、主機、應用客戶以及其他需要唯一值的情況,UUID可以用來生成標識符。這個RFC特別強調創建一個統一資源名(Uniform Resource Name)命名空間,並且涵蓋了3個主要算法。

  • 使用IEEE802MAC地址作為唯一性來源
  • 使用偽隨機數
  • 使用公開的串並結合密碼散列

在上述所有情況下,種子值都要與系統時鍾結合,如果向后設置時鍾,則要用一個時鍾序列值維護唯一性。

1.1 UUID1: IEEE 802 MAC地址

UUID1值使用主機的MAC地址計算。uuid模塊使用getnode()來獲取當前系統的MAC值。

import uuid

print(hex(uuid.getnode()))

如果一個系統有多個網卡,那么相應地便會有多個MAC地址,並且可能返回其中任意一個值。

要為一個主機(由其MAC地址標識)生成一個UUID,需要使用uuid1()函數。節點標識符參數是可選的;如果沒有設置這個域,那么便會使用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('  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對象,可以通過只讀的實例屬性訪問它的各個部分。有些屬性是UUID值的不同表示,如hex、int和urn。

由於有時間分量(time),所以每次調用uuid1()都會返回一個新值。

import uuid

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

在這個輸出中,只有時間分量(串的開始部分)有變化。

由於每個計算機有不同的MAC地址,所以在不同系統上運行這個示例程序會生成完全不同的值。下一個例子傳遞不同的節點ID來模擬在不同主機上運行。

import uuid

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

除了返回不同的時間值,UUID末尾的節點標識符也有變化。

1.2 UUID 3和5 基於名字的值

有些情況下可能需要根據名字創建UUID值,而不是根據隨機值或基於時間的值來創建。UUID3和5規范使用密碼散列值(分別使用MD5或SHA-1),將特定於命名空間的種子值與名字相結合。有一些由預定義UUID值標識的公開的命名空間,分別用於處理DNS、URL、ISO OID和X.500識別名(Distinguished Name)。通過生成和保存UUID值,還可以定義新的特定於應用的命名空間。

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()

要從一個DNS名創建UUID,可以把uuid.NAMESPACE_DNS作為命名空間參數傳入uuid3()或uuid5()。

不論什么時間計算或者在哪里計算,一個命名空間中給定名的UUID值總是相同的。

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()

但是命名空間中相同名字的UUID值則是不同的。

1.3 UUID 4 隨機數

有時,基於主機和基於命名空間的UUID值“差別還不夠大”。例如,如果UUID要作為散列鍵,則需要有區分度更大、更隨機的值序列來避免散列表中出現沖突。讓值有更少的共同數字也能更容易地在日志文件中查找這些值。為了增加UUID的區分度,可以使用uuid4()利用隨機的輸入值生成UUID。

import uuid

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

隨機性的來源取決於導入uuid時哪些C庫可用。如果可以加載libuuid(或uuid.d11),而且其中包含一個生成隨機值的函數,那么便使用這個函數。否則,使用os.urandom()或random模塊。

1.4 處理UUID對象

除了生成新的UUID值,還可以解析標准格式的串以創建UUID對象,使比較和排序操作的處理更為容易。

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:的前綴,則這個前綴也會被刪除。剩下的文本必然是由十六進制數構成的串,然后再將它解釋為一個UUID值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM