当前位置: 首页 > news >正文

Pythonuuid与唯一标识

Python uuid 与唯一标识
==============================

uuid 模块生成统一唯一标识符 (UUID), 有多种版本满足不同场景。

1. uuid1 — 基于时间的 UUID
-----------------------------

import uuid

# UUID1: 基于当前时间戳 + 节点(MAC地址) + 时钟序列
# 优势: 时间有序, 可追踪生成时间
# 劣势: 会暴露 MAC 地址 (隐私问题)
u1 = uuid.uuid1()
print("UUID1:", u1)
print("UUID1 十六进制:", u1.hex) # 32 字符十六进制
print("UUID1 版本:", u1.version) # 1

# UUID1 字段解析
print("时间戳字段:", u1.time) # 100纳秒为单位的时间戳
print("时钟序列:", u1.clock_seq) # 时钟序列 (14位)
print("节点(MAC):", u1.node) # 48位 MAC 地址

# 自定义节点: 避免暴露真实 MAC 地址
custom_node = 0x123456789ABC
u1_custom = uuid.uuid1(node=custom_node)
print("自定义节点 UUID1:", u1_custom)

# 自定义时钟序列
u1_clock = uuid.uuid1(clock_seq=0x3FFF) # 时钟序列范围 0-0x3FFF
print("自定义时钟 UUID1:", u1_clock)

# 从 UUID1 提取时间
from datetime import datetime, timezone
time_100ns = u1.time - 0x01b21dd213814000 # UUID1 时间的偏移量
timestamp_sec = time_100ns / 10000000
dt = datetime.fromtimestamp(timestamp_sec, tz=timezone.utc)
print("UUID1 生成时间 (UTC):", dt)

2. uuid4 — 随机 UUID
----------------------

import uuid

# UUID4: 完全随机生成 (122位随机数 + 6位版本/变体位)
# 优势: 无隐私泄露, 适合大多数应用场景
# 劣势: 无序, 数据库索引性能稍差
u4 = uuid.uuid4()
print("UUID4:", u4)
print("UUID4 版本:", u4.version) # 4
print("UUID4 字节:", u4.bytes) # 16字节原始数据
print("UUID4 整数表示:", u4.int) # 128位整数

# 生成批量 UUID (列表推导式)
batch = [uuid.uuid4() for _ in range(5)]
print("批量 UUID4:")
for i, uid in enumerate(batch):
print(f" {i+1}: {uid}")

# UUID4 碰撞概率: 极其微小
# 每秒生成 10 亿个 UUID4, 约 100 年后才可能发生一次碰撞
# 公式: 碰撞概率 ~ n^2 / (2 * 2^122)

3. uuid3 / uuid5 — 基于名称的 UUID
--------------------------------------

import uuid

# UUID3: 基于命名空间 + 名称的 MD5 哈希 (128位)
# UUID5: 基于命名空间 + 名称的 SHA-1 哈希 (128位)

# 预定义命名空间:
# NAMESPACE_DNS — 域名
# NAMESPACE_URL — URL
# NAMESPACE_OID — ISO OID
# NAMESPACE_X500 — X.500 DN

# UUID5: SHA-1 版 (推荐)
ns_dns = uuid.NAMESPACE_DNS
u5_domain = uuid.uuid5(ns_dns, "example.com")
print("UUID5 (DNS):", u5_domain) # 对 example.com 的一致 UUID

# 同一名称在同一命名空间下总是生成相同 UUID
u5_domain2 = uuid.uuid5(ns_dns, "example.com")
print("UUID5 相同:", u5_domain == u5_domain2) # True

# UUID3: MD5 版 (兼容旧系统)
u3_domain = uuid.uuid3(ns_dns, "example.com")
print("UUID3 (DNS):", u3_domain)
print("UUID3 长度:", len(u3_domain.hex)) # 32

# 不同命名空间下相同名称不同结果
u5_url = uuid.uuid5(uuid.NAMESPACE_URL, "example.com")
print("UUID5 (URL):", u5_url) # 与 DNS 版不同

# 实用场景: 为资源生成确定性 UUID
def resource_uuid(resource_type, resource_id):
"""为资源生成稳定的 UUID5 标识"""
ns = uuid.uuid5(uuid.NAMESPACE_DNS, "myapp.example.com")
return uuid.uuid5(ns, f"{resource_type}:{resource_id}")

user_uuid = resource_uuid("user", "alice")
post_uuid = resource_uuid("post", "12345")
print("用户 UUID:", user_uuid)
print("文章 UUID:", post_uuid)

4. UUID 对象字段与操作
-------------------------

import uuid

u = uuid.uuid4()

# 基本字段
print("UUID 字符串:", str(u)) # 标准格式: 8-4-4-4-12
print("UUID hex:", u.hex) # 32字符十六进制
print("UUID 字节:", u.bytes) # 16字节 (bytes)
print("UUID 字节序 LE:", u.bytes_le) # 混合字节序 (小端 time 域)
print("UUID int:", u.int) # 128位整数表示
print("UUID 变体:", u.variant) # RFC 4122
print("UUID 版本:", u.version) # 4

# UUID 比较和排序
u1 = uuid.uuid4()
u2 = uuid.uuid4()
print("u1 < u2:", u1 < u2) # 按整数值比较
print("相等判断:", u1 == u1) # True

# 从不同格式创建 UUID
u_from_hex = uuid.UUID(hex="550e8400e29b41d4a716446655440000")
u_from_bytes = uuid.UUID(bytes=b"\x55\x0e\x84\x00\xe2\x9b\x41\xd4\xa7\x16\x44\x66\x55\x44\x00\x00")
u_from_int = uuid.UUID(int=0x550e8400e29b41d4a716446655440000)
print("从 hex 创建:", u_from_hex)
print("从 bytes 创建:", u_from_bytes)
print("从 int 创建:", u_from_int)

# UUID 的不可变性
u_frozen = uuid.uuid4()
# u_frozen.int = 123 # 会报错! UUID 不可变

# 将 UUID 用于字典键
cache = {uuid.uuid4(): "value1", uuid.uuid4(): "value2"}
print("UUID 作为字典键:", len(cache))

5. UUID 与数据库主键策略
----------------------------

import uuid

# 场景: 使用 UUID 作为分布式数据库主键
# 优势: 全局唯一, 无需中心化序列, 安全 (不暴露数据量)
# 劣势: 16字节 vs 4字节 int, 索引效率较低

# 策略1: 直接用 UUID 字符串
class ModelWithUUID:
def __init__(self, name: str):
self.id = uuid.uuid4()
self.name = name

def to_db(self):
"""存储到数据库: UUID 转 hex 或 bytes"""
return {
"id_hex": self.id.hex, # 32 字符字符串
"id_bytes": self.id.bytes, # 16 字节 (需 BINARY(16) 类型)
"id_str": str(self.id), # 36 字符字符串
}

entity = ModelWithUUID("测试数据")
print("数据库存储准备:", entity.to_db())

# 策略2: 有序 UUID (类似 UUID1 但更安全)
# 可结合时间戳 + 随机数自行生成有序 UUID
import time
import random

def ordered_uuid():
"""生成时间有序的 UUID (类似 UUID7 方案)"""
# 自定义: 毫秒时间戳(高48位) + 随机数(低80位)
timestamp_ms = int(time.time() * 1000)
rand_bits = random.getrandbits(80)
# 组合成 128 位 UUID
value = (timestamp_ms << 80) | rand_bits
# 设置版本位 (4) 和变体位
value &= ~(0xC000 << 64) # 清除变体位
value |= 0x8000 << 64 # 设置变体 (RFC 4122)
value &= ~(0xF000 << 76) # 清除版本位
value |= 4 << 76 # 设置版本 4
return uuid.UUID(int=value)

print("有序 UUID:", ordered_uuid())

# 策略3: PostgreSQL 的 uuid-ossp 扩展兼容
# PSQL: CREATE EXTENSION "uuid-ossp";
# uuid_generate_v4() -> UUID 类型列

6. Snowflake ID 模式
-------------------------

import time
import threading

class SnowflakeGenerator:
"""简易雪花 ID 生成器 (64位整数, 非 UUID)"""

def __init__(self, worker_id: int, datacenter_id: int, sequence: int = 0):
self.worker_id = worker_id & 0x1F # 5位 工作节点ID
self.datacenter_id = datacenter_id & 0x1F # 5位 数据中心ID
self.sequence = sequence & 0xFFF # 12位 序列号
self.tw_epoch = 1609459200000 # 自定义纪元 (2021-01-01)
self.last_timestamp = -1
self.lock = threading.Lock()

def _current_millis(self) -> int:
return int(time.time() * 1000)

def _wait_next_millis(self, last_ts: int) -> int:
ts = self._current_millis()
while ts <= last_ts:
ts = self._current_millis()
return ts

def next_id(self) -> int:
"""生成下一个 64 位雪花 ID"""
with self.lock:
timestamp = self._current_millis()

# 时钟回拨处理 (简化版, 仅等待)
if timestamp < self.last_timestamp:
timestamp = self._wait_next_millis(self.last_timestamp)

if timestamp == self.last_timestamp:
self.sequence = (self.sequence + 1) & 0xFFF
if self.sequence == 0: # 序列号用完
timestamp = self._wait_next_millis(self.last_timestamp)
else:
self.sequence = 0

self.last_timestamp = timestamp

# 组合: 时间戳(41位) + 数据中心(5位) + 工作节点(5位) + 序列号(12位)
snowflake_id = (
((timestamp - self.tw_epoch) << 22) |
(self.datacenter_id << 17) |
(self.worker_id << 12) |
self.sequence
)
return snowflake_id

def parse(self, snowflake_id: int) -> dict:
"""解析雪花 ID 中的各字段"""
sequence = snowflake_id & 0xFFF
worker_id = (snowflake_id >> 12) & 0x1F
datacenter_id = (snowflake_id >> 17) & 0x1F
timestamp = (snowflake_id >> 22) + self.tw_epoch
return {
"id": snowflake_id,
"timestamp_ms": timestamp,
"datacenter_id": datacenter_id,
"worker_id": worker_id,
"sequence": sequence,
}

# 测试雪花 ID
snowflake = SnowflakeGenerator(worker_id=1, datacenter_id=0)
ids = [snowflake.next_id() for _ in range(3)]
print("雪花 ID 列表:", ids)
for sid in ids:
info = snowflake.parse(sid)
dt = datetime.fromtimestamp(info["timestamp_ms"] / 1000, tz=timezone.utc)
print(f" ID={sid}, 时间={dt}, 数据中心={info['datacenter_id']}, 节点={info['worker_id']}, 序列={info['sequence']}")

7. UUID 的转换与编码
-----------------------

import uuid

# UUID 转不同格式
u = uuid.uuid4()

# 标准 36 字符格式
print("标准格式:", str(u)) # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# 32 字符十六进制 (不带连字符)
print("Hex 格式:", u.hex) # 32 字符

# 16 字节 (二进制紧凑格式)
print("Bytes 格式:", u.bytes) # 16 字节

# Base64 编码 (更紧凑的字符串表示, 22 字符)
import base64
base64_str = base64.urlsafe_b64encode(u.bytes).rstrip(b"=").decode()
print("Base64 格式:", base64_str) # 22 字符

# Base64 解码回 UUID
decoded_bytes = base64.urlsafe_b64decode(base64_str + "==")
restored_uuid = uuid.UUID(bytes=decoded_bytes)
print("恢复 UUID:", restored_uuid)
print("一致?", u == restored_uuid)

# 短 UUID 方案: Base62 编码
BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

def uuid_to_base62(uid: uuid.UUID) -> str:
"""将 UUID 编码为 Base62 字符串 (约 22 字符)"""
num = uid.int
if num == 0:
return BASE62[0]
result = []
while num > 0:
result.append(BASE62[num % 62])
num //= 62
return "".join(reversed(result))

short_id = uuid_to_base62(u)
print("Base62 短 ID:", short_id)
print("长度:", len(short_id)) # 约 22 字符

总结: uuid4 最适合通用场景; uuid5 用于确定性标识; uuid1 用于时间有序; 雪花 ID 适合高性能分布式系统.

http://www.rkmt.cn/news/1422955.html

相关文章:

  • 当微信聊天记录成为数字遗产:一个开源项目的警示与思考
  • Iterative BC-Max:用离线模仿学习优化编译器函数内联决策
  • Keil MDK多目标配置导致文件重复显示的解决方案
  • iStore终极指南:5分钟掌握OpenWRT应用商店的完整使用方法
  • 用数据说话!盘点2026年冠绝行业的的AI论文网站
  • Anthropic完成650亿美元H轮融资,估值达9650亿美元,多家巨头助力算力扩张
  • 口碑爆棚!专攻临床内科主任医师考试的好老师推荐! - 医考机构品牌测评专家
  • 为什么92%的内容团队还在手动运营?Lindy自动化工作流的7个致命断点与修复清单(内部泄露版)
  • PythonTrie前缀树实现
  • 基于图像识别的游戏自动化架构深度解析:E7Helper技术实现原理与设计哲学
  • 2026上海App软件开发公司TOP10推荐,一线大厂与实力派企业全解析
  • 如何为OBS Studio搭建专业级无线视频传输系统:DistroAV完全指南
  • 2026年最受好评的高温含硅脱模剂品牌推荐 - 企业推荐官【官方】
  • 从零开始:互联网大厂 Java 求职者面试之旅——技术栈与场景分析
  • 第九篇:《Dockerfile 指令精讲(二):WORKDIR、ENV、ARG、EXPOSE》
  • 深度解析黄金回收定价逻辑,乌鲁木齐黄金回收首选永盛黄金首饰店 - 企业推荐官【官方】
  • 023、YOLOv6 EfficientRep 重参数化 backbone 原理解析与训练-部署两阶段策略
  • WechatExporter深度解析:从iTunes备份到聊天记录导出的技术实现
  • 论文被批“不够学术”?高校教授说用这几个AI写作辅助软件
  • 3分钟掌握:B站缓存视频无损转换的智能方案
  • 2026论文隐藏级降AIGC工具大曝光:三步直降AIGC率至安全阈值!
  • Java开发者面试:从电商场景到微服务架构的深入探讨
  • 树莓派摄像头实时视频流服务器搭建:Flask+PiCamera实战指南
  • 手把手调参:解决IMU倾斜安装导致的车载组合导航漂移问题(附Python验证代码)
  • 给编程者的微积分课:用Python可视化理解函数连续、可导与洛必达法则
  • 保姆级教程:在 Qt 中为你的点云显示窗口添加鼠标交互(旋转/平移/缩放)与网格坐标轴
  • 别再手动画图了!用Graphviz+Python自动生成流程图,5分钟搞定复杂关系图
  • 土壤尿液电池:微功率物联网的可持续能源解决方案
  • 保姆级教程:用HFSS 2023 R2设计24GHz微带雷达天线(从单元到阵列,附模型文件)
  • Mac用户福音:在Parallels Desktop里跑VMware虚拟机,保姆级避坑指南(解决VT-x/Device Guard报错)