ToolDeck

สร้าง UUID v4 ด้วย Python

·Backend Developer·ตรวจสอบโดยDmitri Volkov·เผยแพร่เมื่อ

ใช้ เครื่องสร้าง UUID v4 ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง

ลอง เครื่องสร้าง UUID v4 ออนไลน์ →

ทุกครั้งที่ต้องการ identifier ที่ป้องกันการชนกันสำหรับแถวในฐานข้อมูล API trace หรือ session token คำตอบคือ การสร้าง UUID v4 ใน Python — เพียงหนึ่งบรรทัด ไม่ต้องพึ่ง dependency ใดเลย: uuid.uuid4(). โมดูล uuid ที่มีใน Python ใช้ os.urandom() เพื่อความสุ่มที่มีความปลอดภัยเชิงการเข้ารหัส หากต้องการ UUID อย่างรวดเร็วโดยไม่ต้องเขียนโค้ด ตัวสร้าง UUID v4 ออนไลน์ ใช้งานได้ทันที คู่มือนี้ครอบคลุม attribute ของออบเจกต์ UUID การสร้างจำนวนมาก การแปลงเป็น JSON การจัดเก็บในฐานข้อมูล การตรวจสอบ uuid-utils (ทดแทนแบบ drop-in ด้วย Rust ที่เร็วกว่า ~10 เท่า) และข้อผิดพลาดที่พบบ่อย 4 ประการ — ทั้งหมดรองรับ Python 3.8+

ประเด็นสำคัญ
  • uuid.uuid4() มีใน stdlib ของ Python แล้ว — แค่ import uuid ก็พอ ไม่ต้องติดตั้งด้วย pip
  • ค่าที่ได้คือออบเจกต์ uuid.UUID ไม่ใช่สตริง — ใช้ str(), .hex หรือ .bytes เพื่อเลือกรูปแบบที่เหมาะกับ storage layer ของคุณ
  • UUID v4 ใช้บิตสุ่ม 122 บิตจาก os.urandom() — มีความปลอดภัยเชิงการเข้ารหัส ไม่เปิดเผย MAC address หรือ timestamp
  • สำหรับบริการ throughput สูง pip install uuid-utils เป็น drop-in replacement ที่เร็วกว่า ~10 เท่า ขับเคลื่อนด้วย Rust
  • อย่าส่ง uuid.uuid4 (ไม่มีวงเล็บ) เป็น default argument โดยตรงใน dataclass หรือ Pydantic model — จะทำให้ทุก instance ใช้ UUID เดียวกัน

UUID v4 คืออะไร?

UUID (Universally Unique Identifier) คือ label ขนาด 128 บิต ที่จัดรูปแบบเป็น เลขฐานสิบหก 32 หลัก แบ่งเป็น 5 กลุ่มด้วยเครื่องหมายขีด: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. เวอร์ชัน 4 เป็น variant ที่นิยมใช้มากที่สุด: 122 ใน 128 บิตถูกสร้างแบบสุ่ม และอีก 6 บิตที่เหลือเข้ารหัสเวอร์ชัน (4) และ variant (RFC 4122) ไม่มี timestamp และไม่มี host identifier — identifier นี้ทึบแสงและปลอดภัยด้านความเป็นส่วนตัวโดยสมบูรณ์ โอกาสที่ UUID v4 สองค่าที่สร้างแยกกันจะชนกันนั้นน้อยมากจนไม่มีผลในทางปฏิบัติ แม้ในระบบกระจายที่สร้าง 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() — วิธีมาตรฐานในการสร้าง UUID v4 ใน Python

โมดูล uuid เป็นส่วนหนึ่งของ standard library ของ Python การเรียก uuid.uuid4() คืนค่าออบเจกต์ uuid.UUID พร้อม attribute ครบชุดสำหรับแสดงผลในรูปแบบต่างๆ การแปลงเป็นสตริงด้วย str() จะได้รูปแบบมาตรฐานพร้อมเครื่องหมายขีดที่ API ฐานข้อมูล และ HTTP header คาดหวัง

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 headers
print(str(request_id))      # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
print(request_id.hex)       # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" (ไม่มีเครื่องหมายขีด)
print(request_id.bytes)     # b';...' (16 raw bytes)

รูปแบบที่พบบ่อยในการใช้งานจริงคือการแนบ UUID กับทุก API request ขาออก เพื่อให้สามารถติดตาม log ข้ามบริการได้ ต่อไปนี้เป็น requests session wrapper ขั้นต่ำที่แทรก UUID ใหม่ในทุกการเรียก:

Python 3.8+ — trace ID ต่อ request
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"] ช่วยให้ grep หา request นั้นใน log ทุก service ได้
result = call_api("https://api.example.com/v1/orders", {"product_id": "prod_7x2k", "qty": 3})
print(result["trace_id"])  # e.g. "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"

เมื่อต้องสร้าง UUID จำนวนมาก เช่น การเตรียม batch แถวในฐานข้อมูลล่วงหน้า การใช้ list comprehension เป็นวิธีที่ดูเป็นธรรมชาติและอ่านง่าย:

Python 3.8+ — สร้างจำนวนมาก
import uuid

# สร้าง ID ล่วงหน้าสำหรับ 1000 telemetry event
event_ids = [str(uuid.uuid4()) for _ in range(1000)]
print(f"Generated {len(event_ids)} unique IDs")
print(event_ids[0])   # e.g. "a1c2e3f4-..."
print(event_ids[-1])  # ค่าต่างกันทุกครั้ง

ต้องการ UUID ด่วนโดยไม่ต้องรันโค้ด? ใช้ ตัวสร้าง UUID v4 ออนไลน์ เพื่อคัดลอกค่าใหม่ในคลิกเดียว หรือสร้างหลายร้อยค่าพร้อมกัน — มีประโยชน์สำหรับ การ seed ฐานข้อมูลทดสอบหรือการใส่ข้อมูลใน fixture file

หมายเหตุ:uuid.uuid4() เรียกใช้ os.urandom(16) ภายใน จากนั้นกำหนด bits 6–7 ของ byte 8 เป็น 10 (variant) และ bits 12–15 ของ byte 6 เป็น 0100 (version 4) ส่วน 122 บิตที่เหลือเป็นค่าสุ่ม นี่คือเหตุผลที่ไม่ควรไว้วางใจ version โดยไม่แปลงด้วย uuid.UUID()

Attribute และรูปแบบการแสดงผลของออบเจกต์ UUID

ออบเจกต์ uuid.UUID เปิดเผยรูปแบบต่างๆ ของค่า 128 บิตเดียวกัน การเลือกรูปแบบที่เหมาะสมกับ storage layer ป้องกันการเสียหายของข้อมูลแบบเงียบและการสิ้นเปลืองพื้นที่

แอตทริบิวต์ / เมธอด
ประเภท
คำอธิบาย
uuid.UUID(hex=...)
UUID
แปลง UUID จาก hex string ที่มีหรือไม่มีเครื่องหมายขีดคั่น
.hex
str
hex string ตัวพิมพ์เล็ก 32 ตัวอักษร ไม่มีเครื่องหมายขีด — รูปแบบจัดเก็บที่กะทัดรัด
.int
int
แสดง UUID ในรูปแบบจำนวนเต็ม 128 บิต — ใช้สำหรับการคำนวณและการเรียงลำดับ
.bytes
bytes
ข้อมูลไบนารี big-endian ขนาด 16 ไบต์ — ขนาดจัดเก็บที่ประหยัดที่สุด
.bytes_le
bytes
ข้อมูลไบนารี little-endian ขนาด 16 ไบต์ — ตรงกับลำดับไบต์ของ Microsoft GUID
.fields
tuple
ทูเพิล 6 ค่าของฟิลด์ UUID: (time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node)
.version
int | None
หมายเลขเวอร์ชันของ UUID (1–5 หรือ None สำหรับ UUID ที่ไม่เป็นมาตรฐาน)
.variant
str
สตริงระบุ variant ของ UUID — "specified in RFC 4122" สำหรับ UUID มาตรฐาน
str(uuid_obj)
str
สตริงมาตรฐาน 36 ตัวอักษรพร้อมเครื่องหมายขีด 4 ตัว: 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 bytes, big-endian)
print(u.bytes_le)     # b'Š...'                       (16 bytes, little-endian)
print(u.int)          # 78823... (จำนวนเต็ม 128 บิต)
print(u.version)      # 4
print(u.variant)      # 'specified in RFC 4122'

# Round-trip: สร้างใหม่จากสตริง
reconstructed = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
print(reconstructed == u)  # True (ถ้า u มีค่านั้น)

สำหรับ PostgreSQL ที่ใช้ psycopg2 หรือ asyncpg ส่งออบเจกต์ UUID ได้โดยตรง — driver จัดการการแมปกับประเภทคอลัมน์ uuid โดยอัตโนมัติ สำหรับ SQLite ใช้ str(u) (TEXT) หรือ u.bytes (BLOB 16 bytes เทียบกับ 36 bytes ของสตริง) สำหรับประสิทธิภาพการจัดเก็บในปริมาณมาก .bytes เล็กกว่าสตริงมาตรฐานถึง 55%

การตรวจสอบและแปลงสตริง UUID v4 ใน Python

เมื่อ UUID มาจาก user input, URL path parameter หรือ upstream API ควรตรวจสอบก่อนใช้เป็น database key วิธีที่เป็นธรรมชาติคือลองสร้างด้วย uuid.UUID() แล้วจับ ValueError. นอกจากนี้ยังสามารถบังคับให้ค่าที่รับเป็น version 4 โดยตรวจสอบ .versionได้ด้วย

Python 3.8+ — ฟังก์ชันตรวจสอบ
import uuid

def parse_uuid4(raw: str) -> uuid.UUID:
    """
    Parse and validate a UUID v4 string.
    Raises ValueError for invalid format or wrong version.
    """
    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 route handler
def get_order(order_id: str):
    try:
        uid = parse_uuid4(order_id)
    except ValueError as exc:
        return {"error": str(exc)}, 400

    # ปลอดภัยที่จะใช้ uid ใน DB query แล้ว
    return {"order_id": str(uid), "status": "processing"}
หมายเหตุ:uuid.UUID() รับสตริงที่มีหรือไม่มีเครื่องหมายขีด และยังรับคำนำหน้า urn:uuid: ได้ด้วย ดังนั้น "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" (ไม่มีเครื่องหมายขีด) และ "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" ทั้งสองแปลงเป็น ออบเจกต์เดียวกัน

UUID v4 ใน JSON Payload และ API Response

มาตรฐาน JSON ไม่มีประเภท UUID — UUID ใน JSON จึงเป็นสตริงเสมอ ซึ่งหมายความว่า ต้องแปลงออบเจกต์ uuid.UUID เป็นสตริงก่อนส่งให้ json.dumps(). วิธีที่สะอาดที่สุดคือ subclass JSONEncoder เพื่อไม่ต้องกระจาย str() calls ทั่ว codebase

Python 3.8+ — JSONEncoder กำหนดเองสำหรับ UUID
import json
import uuid
from datetime import datetime

class ApiEncoder(json.JSONEncoder):
    """Serialize UUID and datetime objects in JSON responses."""
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return str(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

# API response จริงที่มี UUID ซ้อนกัน
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-...",
#     ...
#   }
# }

สำหรับการแปลงครั้งเดียว hook default= ง่ายกว่าการ subclass:

Python 3.8+ — hook default= (ใช้ครั้งเดียว)
import json, uuid

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

# ส่ง callable; เรียกใช้เฉพาะประเภทที่ json จัดการไม่ได้
json_str = json.dumps(payload, default=str)
print(json_str)  # {"event_id": "3b1f8a9d-...", "action": "checkout"}

เมื่อรับ response จาก external API ให้แปลงสตริง UUID กลับเป็นออบเจกต์ เพื่อให้โค้ดได้รับ attribute ครบชุดและ type safety:

Python 3.8+ — แปลง UUID จาก API response
import json
import uuid
import requests

def fetch_shipment(shipment_id: str) -> dict:
    """Fetch a shipment and return with typed UUID fields."""
    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()

    # Parse the UUID fields back to uuid.UUID objects
    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

สำหรับการอัปเดตฟิลด์ UUID ในไฟล์ JSON บนดิสก์ เช่น การเปลี่ยน correlation ID ใน config หรือ seed file — อ่าน แก้ไข และเขียนกลับอย่างปลอดภัย:

Python 3.8+ — อ่าน อัปเดต และเขียนไฟล์ JSON
import json, uuid

def rotate_correlation_id(path: str) -> str:
    """Replace or add 'correlation_id' in a JSON file. Returns the new 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

หากไม่ต้องการรันสคริปต์ทุกครั้งที่ต้องตรวจสอบ UUID จาก API response ให้วางใน UUID Decoder — แสดงเวอร์ชัน variant และทุกฟิลด์โดยไม่ต้องเขียนโค้ดเลย

สร้าง UUID v4 จาก Command Line ด้วย Python

โมดูล uuid ของ Python ไม่มี CLI subcommand แบบ standalone เหมือน python -m json.tool, แต่ one-liner ครอบคลุมการใช้งานเดียวกัน มีประโยชน์ใน shell script, CI pipeline และเมื่อต้องการ identifier ชั่วคราวโดยไม่ต้องเปิด REPL

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

# รูปแบบ hex ไม่มีเครื่องหมายขีด — เหมาะสำหรับ filename และ env var
python3 -c "import uuid; print(uuid.uuid4().hex)"
# 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e

# สร้าง 5 UUID สำหรับ batch seed script
python3 -c "import uuid; [print(uuid.uuid4()) for _ in range(5)]"

# ใช้ใน shell variable
DEPLOY_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
echo "Deploying with ID: $DEPLOY_ID"
หมายเหตุ:บน macOS และ Linux ส่วนใหญ่ uuidgen (ยูทิลิตี C) สร้างค่า UUID v4 และเร็วกว่าสำหรับ shell script ล้วนๆ ใช้ Python one-liner เมื่ออยู่ในสภาพแวดล้อมที่เน้น Python และต้องการความสอดคล้องกับวิธีที่สร้าง UUID ในโค้ดแอปพลิเคชัน

UUID v4 ประสิทธิภาพสูงด้วย uuid-utils

uuid.uuid4() ของ standard library เร็วพอสำหรับแอปพลิเคชันส่วนใหญ่ — ใช้เวลาไม่กี่ไมโครวินาทีต่อการเรียก รองรับการสร้าง ID นับพัน ID ต่อวินาทีได้สบาย หากสร้าง UUID บน hot path ของบริการ throughput สูง (bulk insert, telemetry ต่อ event ขนาดใหญ่ หรือการสร้าง request ID ภายใต้โหลดหนัก) uuid-utils เป็น drop-in replacement ที่รองรับโดย Rust และ benchmark ได้ประมาณ 10 เท่าของ stdlib

bash — install
pip install uuid-utils
Python 3.8+ — uuid-utils drop-in replacement
# uuid_utils is a drop-in replacement for the stdlib uuid module
import uuid_utils as uuid

# Same API as stdlib
request_id = uuid.uuid4()
print(request_id)           # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(request_id))      # canonical string
print(request_id.hex)       # no-dashes hex
print(request_id.version)   # 4

# Also supports v7 (time-ordered, great for DB primary keys)
time_ordered_id = uuid.uuid7()
print(time_ordered_id)      # starts with current-timestamp prefix
คำเตือน:โหมดปกติของ uuid-utils คืนค่าออบเจกต์ UUID ประเภทของตัวเองซึ่งเข้ากันได้กับ stdlib ในกรณีส่วนใหญ่ หากต้องการตรวจสอบ isinstance(u, uuid.UUID) จาก standard library อย่างเข้มงวด ให้ใช้ compat mode: import uuid_utils.compat as uuid. Compat mode ช้ากว่าโหมดปกติเล็กน้อยแต่ยังเร็วกว่า stdlib อยู่

UUID v4 ใน Dataclass และ Pydantic Model

ทั้ง Python dataclass และ Pydantic model รองรับฟิลด์ UUID โดยธรรมชาติ รูปแบบสำคัญเมื่อใช้ UUID เป็น default ที่สร้างอัตโนมัติคือการส่ง reference ของฟังก์ชัน ไม่ใช่ผลลัพธ์จากการเรียกฟังก์ชัน — มิฉะนั้นทุก instance จะใช้ UUID เดียวกัน

Python 3.10+ — dataclass พร้อม UUID default
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)  # unique per instance
print(job2.job_id)  # different from job1.job_id
print(job1.job_id == job2.job_id)  # False
Python 3.10+ — Pydantic v2 model พร้อม UUID
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 serializes uuid.UUID as string automatically

ข้อผิดพลาดที่พบบ่อยในการสร้าง UUID v4 ใน Python

รูปแบบทั้งสี่นี้มักปรากฏใน code review และ production incident — พลาดได้ง่ายเพราะไม่เกิด error ทันที

เรียก uuid4 ไม่มีวงเล็บเป็น Default

ปัญหา: การส่ง uuid.uuid4 (ออบเจกต์ฟังก์ชัน) เป็น default value ใน dataclass หรือ model โดยไม่ห่อด้วย default_factory — Python ประเมิน default เพียงครั้งเดียวตอน class definition ทำให้ทุก instance ใช้ UUID เดียวกัน

วิธีแก้ไข: ใช้ default_factory=uuid.uuid4 ใน dataclass หรือ Field(default_factory=uuid.uuid4) ใน Pydantic เพื่อสร้าง UUID ใหม่ต่อ instance

Before · Python
After · Python
@dataclass
class Session:
    # ผิด: ประเมินครั้งเดียว ทุก instance ใช้ UUID นี้ร่วมกัน
    session_id: uuid.UUID = uuid.uuid4()
@dataclass
class Session:
    # ถูกต้อง: factory ถูกเรียกต่อ instance
    session_id: uuid.UUID = field(default_factory=uuid.uuid4)
เปรียบเทียบออบเจกต์ UUID กับสตริงธรรมดา

ปัญหา: ออบเจกต์ uuid.UUID ไม่เท่ากับสตริงธรรมดา ดังนั้น session_id == '3b1f8a9d-...' จะคืนค่า False เสมอแม้ค่าจะตรงกัน — ทำให้ lookup พังโดยไม่มี error

วิธีแก้ไข: เปรียบเทียบ 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)

# หรือ normalize เป็นสตริงที่จุดขอบเขต:
if str(record["session_id"]) == str(target):
    revoke_session(record)
จัดเก็บ .hex แทน str() และสูญเสียเครื่องหมายขีด

ปัญหา: uuid_obj.hex ให้สตริง 32 ตัวอักษรไม่มีเครื่องหมายขีด ถ้าโค้ดปลายทางคาดหวังรูปแบบมาตรฐาน 36 ตัวอักษรพร้อมเครื่องหมายขีด (ส่วนใหญ่ API และฐานข้อมูลคาดหวังแบบนี้) จะปฏิเสธหรือแปลงค่าผิดพลาดแบบเงียบ

วิธีแก้ไข: ใช้ str(uuid_obj) สำหรับรูปแบบมาตรฐาน 36 ตัวอักษร เว้นแต่มีความต้องการชัดเจนสำหรับรูปแบบ hex แบบกะทัดรัด

Before · Python
After · Python
# จัดเก็บ "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" — ไม่มีเครื่องหมายขีด
payload = {"correlation_id": request_id.hex}
# จัดเก็บ "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" — รูปแบบมาตรฐาน
payload = {"correlation_id": str(request_id)}
ใช้ random.random() หรือ secrets.token_hex() แทน UUID

ปัญหา: random.random() ไม่มีความปลอดภัยเชิงการเข้ารหัส และ secrets.token_hex(16) ให้สตริง hex 32 ตัวอักษรที่ไม่ใช่ UUID ที่ถูกต้อง — ตัวตรวจสอบปลายทางที่เรียก uuid.UUID() จะโยน ValueError

วิธีแก้ไข: ใช้ uuid.uuid4() เมื่อระบบที่รับคาดหวัง identifier รูปแบบ UUID ใช้ secrets.token_hex() เฉพาะเมื่อต้องการ token สุ่มที่ไม่ต้องอยู่ในรูปแบบ UUID

Before · Python
After · Python
import random, secrets

# ไม่ใช่ UUID — จะล้มเหลวเมื่อตรวจสอบด้วย uuid.UUID()
request_id = secrets.token_hex(16)   # "a1b2c3d4e5f6..."
session_id = str(random.random())    # "0.8273..." — ไม่ใกล้เคียงเลย
import uuid

request_id = str(uuid.uuid4())  # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
# Valid UUID v4, cryptographically secure

วิธีสร้าง UUID ใน Python — เปรียบเทียบโดยย่อ

ทุกวิธีด้านล่างสร้าง identifier ขนาด 128 บิต แต่แตกต่างกันที่แหล่งความสุ่ม คุณสมบัติด้านความเป็นส่วนตัว และความต้องการติดตั้ง third-party

วิธีการ
แหล่งที่มา
ความเฉพาะเจาะจง
ปลอดภัยด้านความเป็นส่วนตัว
ประเภทกำหนดเอง
ความเร็ว
การติดตั้ง
uuid.uuid4()
สุ่ม (os.urandom)
2¹²² บิตสุ่ม
N/A
มาตรฐาน
Built-in
uuid.uuid1()
Timestamp + MAC
เวลา + host
❌ (เปิดเผย MAC)
N/A
มาตรฐาน
Built-in
uuid.uuid3(name)
MD5 hash
กำหนดได้ล่วงหน้า
namespace+name
มาตรฐาน
Built-in
uuid.uuid5(name)
SHA-1 hash
กำหนดได้ล่วงหน้า
namespace+name
มาตรฐาน
Built-in
uuid_utils.uuid4()
Rust os.urandom
2¹²² บิตสุ่ม
N/A
~10× เร็วกว่า
pip install uuid-utils
secrets.token_hex(16)
os.urandom
128 บิตสุ่ม
N/A
เร็ว
Built-in
str(uuid.uuid4())
สุ่ม
2¹²² บิตสุ่ม
N/A
มาตรฐาน
Built-in

ใช้ uuid.uuid4() สำหรับ identifier ทั่วไปใน web application ระบบกระจาย และ database primary key เมื่อไม่ต้องการความสามารถในการเรียงลำดับ ใช้ uuid.uuid5() (หรือ v3) สำหรับ ID ที่กำหนดได้จาก namespace และ name ที่รู้จัก เช่น การสร้าง ID ที่คงที่สำหรับ canonical URL เปลี่ยนไปใช้ uuid_utils.uuid7() เมื่อต้องการ ID เรียงตามเวลาสำหรับ database index (หลีกเลี่ยง page split ใน B-tree index ที่ insert rate สูง) และใช้ uuid_utils.uuid4() เมื่อ throughput การสร้างเป็น bottleneck

UUID v4 เทียบกับ UUID v7 — ควรใช้อันไหน?

คำถามที่พบบ่อยที่สุดในทางปฏิบัติคือจะใช้ UUID v4 หรือ UUID v7 ที่ใหม่กว่า สำหรับ database primary key คำตอบสั้นๆ คือ: ใช้ UUID v4 เป็นค่าเริ่มต้น เปลี่ยนเป็น UUID v7 เฉพาะเมื่อ index fragmentation เป็นปัญหาที่วัดได้จริง

ค่า UUID v4 เป็นสุ่มอย่างสมบูรณ์ ซึ่งหมายความว่า insert จะลงที่ตำแหน่งสุ่มใน B-tree index ที่ insert rate ปานกลาง (ไม่กี่ร้อยถึงไม่กี่พัน insert ต่อวินาที) ทำได้ดี — index อยู่ใน buffer pool และการเขียนแบบสุ่มถูก ที่ insert rate สูงมาก การวางแบบสุ่มทำให้เกิด page split และ cache miss บ่อย เพิ่ม write amplification และทำให้ query ช้า

UUID v7 ฝัง Unix timestamp ความแม่นยำ millisecond ในบิตที่มีนัยสำคัญมากที่สุด ดังนั้นแถวที่ insert ใกล้เวลากันจะอยู่ใกล้กันใน index ด้วย ทำให้ B-tree index (PostgreSQL, MySQL, SQLite) ทำงานคล้ายกับ auto-increment integer: แถวใหม่จะต่อท้าย index เสมอ ขจัด page split ข้อเสียคือ UUID v7 เข้ารหัส timestamp ซึ่งเปิดเผยเวลาสร้าง — หลีกเลี่ยงสำหรับ ID ที่ผู้ใช้เห็นเมื่อเวลาสร้างเป็นข้อมูลสำคัญ

ใน Python UUID v7 ยังไม่อยู่ใน standard library (ณ Python 3.12) สร้างได้ด้วย pip install uuid-utils แล้วเรียก uuid_utils.uuid7(). คืนค่าออบเจกต์ที่มี attribute set เดียวกับ uuid.UUID, ดังนั้นการย้ายจาก v4 เปลี่ยนเพียงบรรทัดเดียวใน ID factory

สำหรับทางเลือกที่คลิกเดียวโดยไม่ต้องตั้งค่า Python วาง UUID string ลงใน ตัวสร้างและตัวตรวจสอบ UUID v4 — สร้าง ตรวจสอบ และถอดรหัสทุกฟิลด์ในเบราว์เซอร์

คำถามที่พบบ่อย

จะสร้าง UUID v4 ใน Python ได้อย่างไร?

เรียกใช้ uuid.uuid4() จากโมดูล uuid ที่มีอยู่ใน Python แล้วได้รับออบเจกต์ UUID — แปลงเป็นสตริงด้วย str() เมื่อต้องการใช้เป็นข้อความ โมดูลนี้มาพร้อมกับ standard library จึงไม่ต้องติดตั้งเพิ่มเติมด้วย pip

Python
import uuid

session_id = uuid.uuid4()
print(session_id)           # e.g. 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(session_id))      # same canonical string
print(session_id.hex)       # 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e (no dashes)

uuid.uuid4() กับ str(uuid.uuid4()) แตกต่างกันอย่างไร?

uuid.uuid4() คืนค่าออบเจกต์ UUID ที่มี attribute ต่างๆ เช่น .hex, .bytes, .int และ .version ส่วน str(uuid.uuid4()) แปลงออบเจกต์นั้นเป็นสตริงมาตรฐาน 36 ตัวอักษรทันที ทิ้งออบเจกต์ไป ควรเก็บออบเจกต์ไว้หากต้องการหลายรูปแบบ แต่แปลงเป็นสตริงที่จุดส่งออกเมื่อส่งค่าไปยัง JSON payload ฐานข้อมูล หรือ HTTP header

Python
import uuid

u = uuid.uuid4()
print(type(u))          # <class 'uuid.UUID'>
print(u.version)        # 4
print(u.hex)            # 32-char hex, no dashes
print(u.bytes)          # 16-byte binary
print(str(u))           # canonical 36-char string with dashes

uuid.uuid4() มีความปลอดภัยเชิงการเข้ารหัสหรือไม่?

ใช่ uuid.uuid4() ของ Python ใช้ os.urandom() ภายใน ซึ่งอ่านค่าจากตัวสร้างเลขสุ่มที่มีความปลอดภัยเชิงการเข้ารหัสของระบบปฏิบัติการ (/dev/urandom บน Linux/macOS และ CryptGenRandom บน Windows) บิตสุ่ม 122 บิตทำให้โอกาสชนกันนั้นน้อยมากจนไม่มีผลต่อการใช้งานจริง อย่าสับสนกับ random.random() ซึ่งไม่มีความปลอดภัยเชิงการเข้ารหัส

Python
import uuid, os

# uuid4 เรียกใช้ os.urandom(16) ภายใน
raw = os.urandom(16)
# uuid4 กำหนด version และ variant bits ก่อนส่งคืนค่า
u = uuid.UUID(bytes=raw, version=4)
print(u)  # valid v4 UUID from raw random bytes

จะตรวจสอบว่าสตริงเป็น UUID v4 ที่ถูกต้องใน Python ได้อย่างไร?

แปลงด้วย uuid.UUID() แล้วตรวจสอบ attribute .version ถ้าสตริงไม่ใช่ UUID ที่ถูกต้อง uuid.UUID() จะโยน ValueError — จับ exception เพื่อจัดการ input ที่ไม่ถูกต้อง วิธีนี้ยังตรวจสอบรูปแบบ (เครื่องหมายขีดและความยาว) ด้วย

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, not v4)

จะจัดเก็บ UUID ใน PostgreSQL หรือ SQLite ด้วย Python ได้อย่างไร?

สำหรับ PostgreSQL (ผ่าน psycopg2 หรือ asyncpg) ส่งออบเจกต์ UUID ได้โดยตรง — driver จะแปลงไปยัง native UUID type โดยอัตโนมัติ สำหรับ SQLite ซึ่งไม่มี UUID type โดยตรง ให้จัดเก็บเป็น TEXT ด้วย str(uuid_obj) หรือเป็น BLOB ด้วย uuid_obj.bytes และ SQLAlchemy มีประเภทคอลัมน์ UUID ที่จัดการเรื่องนี้โดยอัตโนมัติทุก dialect

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()
# Reconstruct UUID object from stored string
retrieved_id = uuid.UUID(row[0])
print(retrieved_id.version)  # 4

สามารถสร้าง UUID หลายค่าพร้อมกันใน Python ได้หรือไม่?

ได้ — ใช้ list comprehension หรือ generator โดยการเรียก uuid.uuid4() แต่ละครั้งนั้นเป็นอิสระและรับประกันว่าได้ค่าที่ต่างกัน สำหรับการสร้างจำนวนมากที่ต้องการ throughput สูง uuid-utils (ที่รองรับโดย Rust) เร็วกว่า standard library ประมาณ 10 เท่า

Python
import uuid

# สร้าง 5 trace ID สำหรับ batch request
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 ที่เรียงลำดับตามเวลา — เหมาะสำหรับ primary key ในฐานข้อมูลที่ต้องการลด index fragmentation
  • UUID Decoderตรวจสอบ UUID ใดก็ได้ — เวอร์ชัน, variant, timestamp (v1/v7) และฟิลด์ node โดยไม่ต้องเขียน parser เอง
  • JWT Decoderถอดรหัสและตรวจสอบ JWT token ซึ่งมักบรรจุ UUID ใน claim subject (sub) หรือ jti identifier พร้อม session 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.