Python UUID v4 生成指南

·Backend Developer·审阅者Dmitri Volkov·发布日期

直接在浏览器中使用免费的 UUID v4生成器,无需安装。

在线试用 UUID v4生成器 →

每当我需要为数据库行、API 追踪或会话令牌生成一个无碰撞标识符时,答案都是 在 Python 中生成 UUID v4——一行代码,零依赖: uuid.uuid4()。 Python 内置的 uuid 模块使用 os.urandom() 提供密码学安全的随机性。如果不想写代码, 在线 UUID v4 生成器 可即时使用。本指南涵盖 UUID 对象属性、批量生成、JSON 序列化、数据库存储、验证、 uuid-utils (~10× 更快的 Rust 实现直接替代)以及四个最常见的错误——全部基于 Python 3.8+。

核心要点
  • uuid.uuid4() 内置于 Python 标准库——只需 import uuid,无需 pip install。
  • 返回值是 uuid.UUID 对象,而非字符串——根据存储层需求,使用 str().hex.bytes 选择合适的表示形式。
  • UUID v4 使用来自 os.urandom() 的 122 个随机位——密码学安全,不暴露 MAC 地址或时间戳。
  • 对于高吞吐量服务,pip install uuid-utils 是 Rust 驱动的直接替代,速度约快 10 倍。
  • 永远不要在 dataclass 或 Pydantic 模型中将 uuid.uuid4(不带括号)作为默认参数直接传入——这会导致所有实例共享同一个 UUID。

什么是 UUID v4?

UUID(通用唯一标识符)是一个 128 位标签,格式为 32 个十六进制数字,由连字符分为五组: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。 第 4 版是使用最广泛的变体:128 位中有 122 位是随机生成的,剩余 6 位用于编码版本号(4)和变体(RFC 4122)。它不包含时间戳和主机标识符——标识符完全不透明且保护隐私。 两个独立生成的 v4 UUID 发生碰撞的概率极低,即使在每秒生成数百万个 ID 的分布式系统中,实际上也不会发生碰撞。

Before · Python
After · Python
event_id = "evt-" + str(random.randint(100000, 999999))  # fragile, not unique
event_id = str(uuid.uuid4())  # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e

uuid.uuid4() — 在 Python 中生成 UUID v4 的标准方式

uuid 模块是 Python 标准库的一部分。调用 uuid.uuid4() 返回一个 uuid.UUID 对象,该对象提供多种表示形式的完整属性集。使用 str() 转换为字符串会生成 API、数据库和 HTTP 头所期望的标准连字符格式。

Python 3.8+ — 最简示例
import uuid

# 生成一个 UUID v4
request_id = uuid.uuid4()

print(request_id)           # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(type(request_id))     # <class 'uuid.UUID'>
print(request_id.version)   # 4

# 转换为字符串用于 JSON / HTTP 头
print(str(request_id))      # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
print(request_id.hex)       # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"(无连字符)
print(request_id.bytes)     # b';...'(16 个原始字节)

一个常见的实际场景是为每个出站 API 请求附加一个 UUID,以便跨服务关联日志。下面是一个向每次调用注入新 UUID 的最简 requests 会话封装:

Python 3.8+ — 每请求追踪 ID
import uuid
import requests

def call_api(endpoint: str, payload: dict) -> dict:
    trace_id = str(uuid.uuid4())
    headers = {
        "X-Request-ID": trace_id,
        "Content-Type": "application/json",
    }
    response = requests.post(endpoint, json=payload, headers=headers, timeout=10)
    response.raise_for_status()
    return {"trace_id": trace_id, "data": response.json()}

# result["trace_id"] 可用于在所有服务日志中精确检索该请求
result = call_api("https://api.example.com/v1/orders", {"product_id": "prod_7x2k", "qty": 3})
print(result["trace_id"])  # 例如 "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"

批量生成 UUID 时——例如预填充一批数据库行——列表推导式是惯用且易读的写法:

Python 3.8+ — 批量生成
import uuid

# 为 1000 条遥测事件预生成 ID
event_ids = [str(uuid.uuid4()) for _ in range(1000)]
print(f"Generated {len(event_ids)} unique IDs")
print(event_ids[0])   # 例如 "a1c2e3f4-..."
print(event_ids[-1])  # 每次运行值都不同

需要快速获取 UUID 而不想运行代码?使用 在线 UUID v4 生成器 一键复制新值,或批量生成数百个——适合填充测试数据库或 fixture 文件。

注意:uuid.uuid4() 内部调用 os.urandom(16),然后将第 8 字节的第 6–7 位设为 10(变体),将第 6 字节的第 12–15 位设为 0100(版本 4)。其余 122 位均为随机值。 这就是为什么除非通过 uuid.UUID() 解析,否则不能信任版本字段。

UUID 对象属性与表示形式

uuid.UUID 对象为同一个 128 位值提供了多种表示形式。为存储层选择合适的表示形式,可以防止静默数据损坏和字节浪费。

属性 / 方法
类型
说明
uuid.UUID(hex=...)
UUID
从十六进制字符串解析已有 UUID,支持带或不带连字符的格式。
.hex
str
32 字符的小写十六进制字符串,不含连字符——适合紧凑存储。
.int
int
UUID 的 128 位整数表示——便于算术运算和排序。
.bytes
bytes
16 字节大端序二进制表示——存储效率最高。
.bytes_le
bytes
16 字节小端序二进制——与 Microsoft GUID 字节顺序一致。
.fields
tuple
UUID 字段的六元组:(time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node)。
.version
int | None
UUID 版本号(1–5,非标准 UUID 为 None)。
.variant
str
UUID 变体字符串——标准 UUID 为 "specified in RFC 4122"。
str(uuid_obj)
str
标准 36 字符字符串,含四个连字符:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。
Python 3.8+ — 所有表示形式
import uuid

u = uuid.uuid4()

print(str(u))         # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"  (36 字符)
print(u.hex)          # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"      (32 字符,无连字符)
print(u.bytes)        # b';Š...'                       (16 字节,大端序)
print(u.bytes_le)     # b'Š...'                       (16 字节,小端序)
print(u.int)          # 78823...(128 位整数)
print(u.version)      # 4
print(u.variant)      # 'specified in RFC 4122'

# 往返:从字符串重建
reconstructed = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
print(reconstructed == u)  # True(如果 u 就是该值)

对于使用 psycopg2 或 asyncpg 的 PostgreSQL,直接传入 UUID 对象——驱动程序会自动映射到原生 uuid 列类型。对于 SQLite,使用 str(u) (TEXT)或 u.bytes (BLOB,16 字节 vs 字符串的 36 字节)。对于大规模存储效率, .bytes 比标准字符串小 55%。

在 Python 中验证和解析 UUID v4 字符串

每当 UUID 来自用户输入、URL 路径参数或上游 API 时,在将其用作数据库键之前都应先进行验证。惯用做法是尝试用 uuid.UUID() 构造并捕获 ValueError。 还可以通过检查 .version 来确认传入值是否确实为第 4 版。

Python 3.8+ — 验证辅助函数
import uuid

def parse_uuid4(raw: str) -> uuid.UUID:
    """
    解析并验证 UUID v4 字符串。
    格式无效或版本不符时抛出 ValueError。
    """
    try:
        u = uuid.UUID(raw)
    except ValueError as exc:
        raise ValueError(f"Invalid UUID format: {raw!r}") from exc

    if u.version != 4:
        raise ValueError(f"Expected UUID v4, got v{u.version}: {raw!r}")

    return u

# 在 FastAPI / Flask 路由处理器中使用
def get_order(order_id: str):
    try:
        uid = parse_uuid4(order_id)
    except ValueError as exc:
        return {"error": str(exc)}, 400

    # 现在可以安全地在 DB 查询中使用 uid
    return {"order_id": str(uid), "status": "processing"}
注意:uuid.UUID() 接受带或不带连字符的字符串, 也接受 urn:uuid: 前缀。因此 "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"(无连字符)和 "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" 都能解析为同一个对象。

JSON 载荷与 API 响应中的 UUID v4

JSON 标准没有 UUID 类型——JSON 中的 UUID 始终是字符串。这意味着在将 uuid.UUID 对象传给 json.dumps() 之前必须将其转换为字符串。最简洁的方式是自定义 JSONEncoder 子类,这样就无需在代码库中到处散落 str() 调用。

Python 3.8+ — 自定义 UUID 的 JSONEncoder
import json
import uuid
from datetime import datetime

class ApiEncoder(json.JSONEncoder):
    """在 JSON 响应中序列化 UUID 和 datetime 对象。"""
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return str(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

# 包含嵌套 UUID 的真实 API 响应
api_response = {
    "request_id": uuid.uuid4(),
    "created_at": datetime(2026, 3, 14, 9, 41, 0),
    "order": {
        "id": uuid.uuid4(),
        "customer_id": uuid.uuid4(),
        "items": [
            {"product_id": uuid.uuid4(), "sku": "NVX-9000", "qty": 2},
        ],
    },
}

print(json.dumps(api_response, indent=2, cls=ApiEncoder))
# {
#   "request_id": "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e",
#   "created_at": "2026-03-14T09:41:00",
#   "order": {
#     "id": "a1c2e3f4-...",
#     ...
#   }
# }

对于一次性序列化调用, default= 钩子比子类化更简洁:

Python 3.8+ — default= 钩子(一次性使用)
import json, uuid

event_id = uuid.uuid4()
payload = {"event_id": event_id, "action": "checkout"}

# 传入可调用对象;仅在 json 无法处理的类型时调用
json_str = json.dumps(payload, default=str)
print(json_str)  # {"event_id": "3b1f8a9d-...", "action": "checkout"}

接收外部 API 的响应时,将 UUID 字符串解析回对象,以获得完整的属性集和类型安全:

Python 3.8+ — 从 API 响应中解析 UUID
import json
import uuid
import requests

def fetch_shipment(shipment_id: str) -> dict:
    """获取货运信息并返回带类型化 UUID 字段的结果。"""
    response = requests.get(
        f"https://api.logistics.example.com/v2/shipments/{shipment_id}",
        headers={"Accept": "application/json"},
        timeout=10,
    )
    response.raise_for_status()
    data = response.json()

    # 将 UUID 字段解析回 uuid.UUID 对象
    try:
        data["id"] = uuid.UUID(data["id"])
        data["carrier_id"] = uuid.UUID(data["carrier_id"])
    except (KeyError, ValueError) as exc:
        raise RuntimeError(f"Malformed shipment response: {exc}") from exc

    return data

要更新磁盘上 JSON 文件中的 UUID 字段——例如轮换配置或 seed 文件中的关联 ID——可以读取、修改后原子写回:

Python 3.8+ — 读取、更新并写入 JSON 文件
import json, uuid

def rotate_correlation_id(path: str) -> str:
    """替换或添加 JSON 文件中的 'correlation_id',返回新的 UUID。"""
    try:
        with open(path) as f:
            data = json.load(f)
    except FileNotFoundError:
        data = {}
    except json.JSONDecodeError as exc:
        raise ValueError(f"Invalid JSON in {path!r}: {exc}") from exc

    new_id = str(uuid.uuid4())
    data["correlation_id"] = new_id

    with open(path, "w") as f:
        json.dump(data, f, indent=2)

    return new_id

如果不想每次都运行脚本来检查 API 响应中的 UUID,可以直接粘贴到 UUID Decoder 中——无需任何代码即可查看版本、变体和所有字段。

使用 Python 从命令行生成 UUID v4

Python 的 uuid 模块没有像 python -m json.tool 那样独立的 CLI 子命令,但一行代码就能满足需求。这在 shell 脚本、CI 流水线以及需要临时标识符而不想打开 REPL 时非常实用。

bash
# 单个 UUID v4
python3 -c "import uuid; print(uuid.uuid4())"
# 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e

# 无连字符的十六进制格式——适合文件名和环境变量
python3 -c "import uuid; print(uuid.uuid4().hex)"
# 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e

# 为批量 seed 脚本生成 5 个 UUID
python3 -c "import uuid; [print(uuid.uuid4()) for _ in range(5)]"

# 赋值给 shell 变量
DEPLOY_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
echo "Deploying with ID: $DEPLOY_ID"
注意:在 macOS 和大多数 Linux 发行版上,uuidgen (一个 C 工具)可以生成 UUID v4 值,对于纯 shell 脚本来说速度更快。当你已处于以 Python 为中心的环境中,并希望与应用代码中 UUID 的生成方式保持一致时,使用 Python 单行命令更为合适。

使用 uuid-utils 实现高性能 UUID v4 生成

标准库的 uuid.uuid4() 对大多数应用来说已经足够快——每次调用几微秒,每秒可轻松处理数千个 ID。但如果你在高吞吐量服务的热路径上生成 UUID(批量插入、大规模逐事件遥测或高负载下的请求 ID 生成), uuid-utils 是一个由 Rust 驱动的直接替代方案,基准测试速度约为标准库的 10 倍。

bash — install
pip install uuid-utils
Python 3.8+ — uuid-utils 直接替代
# uuid_utils 是标准库 uuid 模块的直接替代
import uuid_utils as uuid

# 与标准库相同的 API
request_id = uuid.uuid4()
print(request_id)           # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(request_id))      # 标准字符串
print(request_id.hex)       # 无连字符的十六进制
print(request_id.version)   # 4

# 同时支持 v7(时间有序,非常适合数据库主键)
time_ordered_id = uuid.uuid7()
print(time_ordered_id)      # 以当前时间戳前缀开头
警告:uuid-utils 的默认模式返回其自身的 UUID 对象类型,在大多数情况下与标准库兼容。如果需要严格的 isinstance(u, uuid.UUID) 检查(来自标准库), 请使用兼容模式: import uuid_utils.compat as uuid。兼容模式比默认模式稍慢,但仍比标准库更快。

在 Dataclass 和 Pydantic 模型中使用 UUID v4

Python dataclass 和 Pydantic 模型都原生支持 UUID 字段。将 UUID 用作自动生成默认值时,关键模式是传入函数引用,而非调用结果——否则每个实例将共享同一个 UUID。

Python 3.10+ — 带 UUID 默认值的 dataclass
from dataclasses import dataclass, field
import uuid

@dataclass
class WorkerJob:
    job_id: uuid.UUID = field(default_factory=uuid.uuid4)
    worker_id: str = "worker-01"
    payload: dict = field(default_factory=dict)

job1 = WorkerJob(payload={"task": "resize_image", "src": "uploads/img_4932.png"})
job2 = WorkerJob(payload={"task": "send_email",   "to":  "ops@example.com"})

print(job1.job_id)  # 每个实例唯一
print(job2.job_id)  # 与 job1.job_id 不同
print(job1.job_id == job2.job_id)  # False
Python 3.10+ — 带 UUID 的 Pydantic v2 模型
from pydantic import BaseModel, Field
import uuid

class OrderEvent(BaseModel):
    event_id: uuid.UUID = Field(default_factory=uuid.uuid4)
    order_id: uuid.UUID
    status: str
    amount_cents: int

event = OrderEvent(
    order_id=uuid.UUID("a1c2e3f4-5b6d-4e7f-8c9d-0a1b2c3d4e5f"),
    status="payment_confirmed",
    amount_cents=4995,
)

print(event.model_dump_json(indent=2))
# {
#   "event_id": "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e",
#   "order_id": "a1c2e3f4-5b6d-4e7f-8c9d-0a1b2c3d4e5f",
#   "status": "payment_confirmed",
#   "amount_cents": 4995
# }
# Pydantic v2 自动将 uuid.UUID 序列化为字符串

在 Python 中生成 UUID v4 的常见错误

以下四种模式我在代码审查和生产事故中都见过——它们很容易被忽视,因为不会立即报错。

调用 uuid4 时忘加括号作为默认值

问题: 在 dataclass 或模型中将 uuid.uuid4(函数对象)而非调用结果作为默认值,且未包装在 default_factory 中——Python 在类定义时只执行一次默认值,导致所有实例共享同一个 UUID。

解决方法: 在 dataclass 中使用 default_factory=uuid.uuid4,在 Pydantic 中使用 Field(default_factory=uuid.uuid4),这样每个实例都会生成新的 UUID。

Before · Python
After · Python
@dataclass
class Session:
    # 错误:只执行一次,所有实例共享此 UUID
    session_id: uuid.UUID = uuid.uuid4()
@dataclass
class Session:
    # 正确:每个实例调用一次工厂函数
    session_id: uuid.UUID = field(default_factory=uuid.uuid4)
将 UUID 对象与普通字符串进行比较

问题: uuid.UUID 对象与普通字符串不相等,因此即使值匹配,session_id == '3b1f8a9d-...' 也始终返回 False——静默地破坏查找逻辑。

解决方法: 始终将 UUID 与 UUID 比较:比较前用 uuid.UUID() 包装字符串,或将两边都转换为 str()。

Before · Python
After · Python
# 即使值匹配也返回 False
if record["session_id"] == "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e":
    revoke_session(record)
target = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
if record["session_id"] == target:   # 两者都是 uuid.UUID
    revoke_session(record)

# 或在边界处统一转换为字符串:
if str(record["session_id"]) == str(target):
    revoke_session(record)
存储 .hex 而非 str() 导致丢失连字符

问题: uuid_obj.hex 生成 32 字符的无连字符字符串。如果下游代码期望标准的 36 字符带连字符格式(大多数 API 和数据库如此),它将拒绝或静默地错误解析该值。

解决方法: 除非明确需要紧凑十六进制格式,否则使用 str(uuid_obj) 获得标准 36 字符格式。

Before · Python
After · Python
# 存储 "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"——无连字符
payload = {"correlation_id": request_id.hex}
# 存储 "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"——标准格式
payload = {"correlation_id": str(request_id)}
在需要 UUID 时使用 random.random() 或 secrets.token_hex()

问题: random.random() 不具备密码学安全性,而 secrets.token_hex(16) 生成的是 32 字符十六进制字符串,不是有效的 UUID——下游对其调用 uuid.UUID() 的验证器会抛出 ValueError。

解决方法: 当接收方期望 UUID 格式标识符时,使用 uuid.uuid4()。只有在明确需要非 UUID 格式的随机令牌时才使用 secrets.token_hex()。

Before · Python
After · Python
import random, secrets

# 不是 UUID——无法通过 uuid.UUID() 验证
request_id = secrets.token_hex(16)   # "a1b2c3d4e5f6..."
session_id = str(random.random())    # "0.8273..."——根本不像 UUID
import uuid

request_id = str(uuid.uuid4())  # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
# 有效的 UUID v4,密码学安全

Python 中 UUID 生成方法对比

以下所有方法都生成 128 位标识符,但在熵源、隐私特性以及是否需要第三方包方面有所不同。

方法
来源
唯一性
隐私安全
自定义类型
速度
安装
uuid.uuid4()
随机 (os.urandom)
2¹²² 随机位
标准库
内置
uuid.uuid1()
时间戳 + MAC 地址
时间 + 主机
❌(MAC 暴露)
标准库
内置
uuid.uuid3(name)
MD5 哈希
确定性
namespace+name
标准库
内置
uuid.uuid5(name)
SHA-1 哈希
确定性
namespace+name
标准库
内置
uuid_utils.uuid4()
Rust os.urandom
2¹²² 随机位
~10× 更快
pip install uuid-utils
secrets.token_hex(16)
os.urandom
128 随机位
快速
内置
str(uuid.uuid4())
随机
2¹²² 随机位
标准库
内置

在 Web 应用、分布式系统和不要求可排序性的数据库主键场景中,使用 uuid.uuid4() 作为通用唯一标识符。对于从已知命名空间和名称派生的确定性 ID——例如为规范 URL 生成稳定 ID——使用 uuid.uuid5() (或 v3)。当需要用于数据库索引的时间有序 ID 时(可避免高插入率下 B 树索引的页面分裂),改用 uuid_utils.uuid7()。 当原始生成吞吐量成为瓶颈时,使用 uuid_utils.uuid4()

UUID v4 与 UUID v7——该用哪个?

最常见的实际问题是数据库主键应该使用 UUID v4 还是较新的 UUID v7。简短答案:默认使用 UUID v4;只有在索引碎片成为可测量问题时才切换到 UUID v7。

UUID v4 的值完全随机,意味着插入会落在 B 树索引的随机位置。在中等插入速率下(每秒数百到数千次),这完全没问题——索引可以放入缓冲池,随机写入开销可接受。但在极高的插入速率下,随机放置会导致频繁的页面分裂和缓存未命中,增加写放大并降低查询速度。

UUID v7 在最高有效位中嵌入了毫秒精度的 Unix 时间戳,因此时间相近的插入也会落在索引中相邻的位置。这使得 B 树索引(PostgreSQL、MySQL、SQLite)的行为更接近自增整数:新行始终追加到索引末尾,消除了页面分裂。代价是 UUID v7 编码了时间戳,会泄露创建时间——对于创建时间敏感的面向用户的 ID,应避免使用。

在 Python 中,UUID v7 尚未纳入标准库(截至 Python 3.12)。通过 pip install uuid-utils 安装后调用 uuid_utils.uuid7() 即可生成。它返回的对象与 uuid.UUID 具有相同的属性集,因此从 v4 迁移只需修改 ID 工厂中的一行代码。

如需不配置 Python 环境的一键替代方案,可将 UUID 字符串粘贴到 UUID v4 生成与验证器 中——直接在浏览器中生成、验证并解码所有字段。

常见问题

如何在 Python 中生成 UUID v4?

调用 Python 内置 uuid 模块中的 uuid.uuid4()。它返回一个 UUID 对象——需要文本表示时用 str() 转换。该模块随标准库一同提供,无需 pip install。

Python
import uuid

session_id = uuid.uuid4()
print(session_id)           # 例如 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(session_id))      # 同样的标准字符串
print(session_id.hex)       # 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e(无连字符)

uuid.uuid4() 和 str(uuid.uuid4()) 有什么区别?

uuid.uuid4() 返回一个 UUID 对象,该对象具有 .hex、.bytes、.int 和 .version 等属性。str(uuid.uuid4()) 则立即将该对象转换为 36 字符的标准字符串,丢弃对象本身。如果需要多种表示形式,请保留对象;只在需要传递给 JSON 载荷、数据库或 HTTP 头时再转为字符串。

Python
import uuid

u = uuid.uuid4()
print(type(u))          # <class 'uuid.UUID'>
print(u.version)        # 4
print(u.hex)            # 32 字符十六进制,无连字符
print(u.bytes)          # 16 字节二进制
print(str(u))           # 带连字符的标准 36 字符字符串

uuid.uuid4() 是否具有密码学安全性?

是的。Python 的 uuid.uuid4() 内部使用 os.urandom(),该函数读取操作系统的密码学安全随机数生成器(Linux/macOS 上为 /dev/urandom,Windows 上为 CryptGenRandom)。122 个随机位使碰撞概率在任何实际工作负载下都可忽略不计。请勿将其与不具备密码学安全性的 random.random() 混淆。

Python
import uuid, os

# uuid4 内部调用 os.urandom(16)
raw = os.urandom(16)
# uuid4 在返回前设置版本位和变体位
u = uuid.UUID(bytes=raw, version=4)
print(u)  # 由原始随机字节生成的有效 v4 UUID

如何在 Python 中验证字符串是否为有效的 UUID v4?

用 uuid.UUID() 解析并检查 .version 属性。如果字符串不是有效的 UUID,uuid.UUID() 会抛出 ValueError——捕获该异常来处理无效输入。这同时也验证了格式(连字符、长度)的正确性。

Python
import uuid

def is_valid_uuid4(value: str) -> bool:
    try:
        u = uuid.UUID(value)
        return u.version == 4
    except ValueError:
        return False

print(is_valid_uuid4("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"))  # True
print(is_valid_uuid4("not-a-uuid"))                              # False
print(is_valid_uuid4("3b1f8a9d-2c4e-1f6a-8b0d-5e7c9f1a3d2e"))  # False(v1,非 v4)

如何在 Python 中将 UUID 存储到 PostgreSQL 或 SQLite 数据库?

使用 PostgreSQL(通过 psycopg2 或 asyncpg)时,直接传入 UUID 对象——驱动程序会自动适配到原生 UUID 类型。使用 SQLite(无原生 UUID 类型)时,通过 str(uuid_obj) 存为 TEXT,或通过 uuid_obj.bytes 存为 BLOB。SQLAlchemy 提供了 UUID 列类型,可自动跨数据库方言处理。

Python
import uuid
import sqlite3

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE events (id TEXT PRIMARY KEY, name TEXT)")

event_id = uuid.uuid4()
conn.execute("INSERT INTO events VALUES (?, ?)", (str(event_id), "user_signup"))
conn.commit()

row = conn.execute("SELECT * FROM events").fetchone()
# 从存储的字符串重建 UUID 对象
retrieved_id = uuid.UUID(row[0])
print(retrieved_id.version)  # 4

能否在 Python 中一次生成多个 UUID?

可以——使用列表推导式或生成器即可。每次调用 uuid.uuid4() 都是独立的,保证生成不同的值。对于吞吐量要求较高的批量生成场景,uuid-utils(Rust 实现)比标准库快约 10 倍。

Python
import uuid

# 为批量请求预生成 5 个唯一追踪 ID
trace_ids = [str(uuid.uuid4()) for _ in range(5)]
for tid in trace_ids:
    print(tid)
# 每行都是不同的 UUID v4

相关工具

  • UUID v4 Generator直接在浏览器中即时生成 UUID v4,无需 Python 环境。一次复制单个值,或批量生成数百个。
  • UUID v7 Generator生成按时间排序的 UUID v7——可按创建时间排序,适合对索引碎片敏感的数据库主键场景。
  • UUID Decoder检查任意 UUID 的版本、变体、时间戳(v1/v7)和节点字段,无需手写解析器。
  • JWT Decoder解码并检查 JWT 令牌——JWT 通常在 sub 或 jti 字段中携带 UUID 主体声明或会话标识符。
MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

DV
Dmitri Volkov技术审阅者

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.