ToolDeck

تولید UUID v4 با Python — راهنمای کامل uuid.uuid4()

·Backend Developer·بررسی‌شده توسطDmitri Volkov·منتشر شده

از تولیدکننده UUID v4 آنلاین رایگان مستقیم در مرورگرتان استفاده کنید — نیازی به نصب نیست.

امتحان کردن تولیدکننده UUID v4 آنلاین ←

هر بار که به یک شناسه مقاوم در برابر تصادم برای ردیف پایگاه داده، ردیابی API، یا توکن session نیاز دارم، پاسخ تولید UUID v4 در Python است — یک خط، بدون وابستگی: uuid.uuid4(). ماژول داخلی uuid در Python از os.urandom() برای تصادفی‌سازی امن از نظر رمزنگاری استفاده می‌کند. برای یک UUID سریع بدون نوشتن کد، مولد آنلاین UUID v4 فوراً کار می‌کند. این راهنما ویژگی‌های شیء UUID، تولید انبوه، سریال‌سازی JSON، ذخیره‌سازی در پایگاه داده، اعتبارسنجی، uuid-utils (جایگزین با پشتیبانی Rust که ~۱۰× سریع‌تر است)، و چهار اشتباه رایج را پوشش می‌دهد — همه با Python 3.8+.

نکات کلیدی
  • uuid.uuid4() در stdlib Python داخلی است — import uuid تنها چیزی است که نیاز دارید، بدون نصب pip.
  • مقدار بازگشتی یک شیء uuid.UUID است نه رشته — از str()، .hex، یا .bytes برای انتخاب نمایش مناسب لایه ذخیره‌سازی خود استفاده کنید.
  • UUID v4 از ۱۲۲ بیت تصادفی از os.urandom() استفاده می‌کند — امن از نظر رمزنگاری، بدون افشای آدرس MAC یا timestamp.
  • برای سرویس‌های با توان عملیاتی بالا، pip install uuid-utils یک جایگزین drop-in است که ~۱۰ برابر سریع‌تر است و با Rust پشتیبانی می‌شود.
  • هرگز uuid.uuid4 (بدون پرانتز) را به عنوان آرگومان پیش‌فرض مستقیم در یک dataclass یا مدل Pydantic پاس ندهید — یک UUID واحد را در همه instance‌ها به اشتراک می‌گذارد.

UUID v4 چیست؟

یک UUID (Universally Unique Identifier) یک برچسب ۱۲۸ بیتی است که به صورت ۳۲ رقم هگزادسیمال تقسیم‌شده به پنج گروه با خط تیره فرمت می‌شود: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. نسخه ۴ پرکاربردترین variant است: ۱۲۲ بیت از آن ۱۲۸ بیت به صورت تصادفی تولید می‌شوند، و ۶ بیت باقی‌مانده نسخه (۴) و variant (RFC 4122) را کدگذاری می‌کنند. هیچ timestamp و هیچ شناسه میزبانی وجود ندارد — شناسه کاملاً مبهم و ایمن از نظر حریم خصوصی است. احتمال تصادم دو UUID v4 که به طور مستقل تولید شده‌اند آنقدر کم است که برای اهداف عملی هرگز اتفاق نمی‌افتد، حتی در سیستم‌های توزیع‌شده که میلیون‌ها شناسه در ثانیه تولید می‌کنند.

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

uuid.uuid4() — روش استاندارد برای تولید UUID v4 در Python

ماژول 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';...' (۱۶ بایت خام)

یک الگوی رایج در دنیای واقعی، اتصال یک UUID به هر درخواست API خروجی است تا بتوانید لاگ‌ها را در سرویس‌های مختلف همبسته کنید. در اینجا یک wrapper ساده برای requests session است که یک UUID جدید به هر فراخوانی تزریق می‌کند:

Python 3.8+ — trace 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"] به شما امکان می‌دهد این درخواست دقیق را در لاگ‌های همه سرویس‌ها grep کنید
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‌ها — برای مثال، پیش‌پر کردن یک دسته از ردیف‌های پایگاه داده — list comprehension اصولی و خوانا است:

Python 3.8+ — تولید انبوه
import uuid

# پیش‌تولید ID برای ۱۰۰۰ رویداد telemetry
event_ids = [str(uuid.uuid4()) for _ in range(1000)]
print(f"تولید شد {len(event_ids)} ID یکتا")
print(event_ids[0])   # مثال: "a1c2e3f4-..."
print(event_ids[-1])  # هر بار مقدار متفاوتی

به یک UUID سریع بدون اجرای کد نیاز دارید؟ از مولد آنلاین UUID v4 برای کپی کردن یک مقدار تازه با یک کلیک استفاده کنید، یا صدها مورد را به صورت انبوه تولید کنید — مفید برای seed کردن پایگاه‌های داده آزمایشی یا پر کردن فایل‌های fixture.

یادداشت:uuid.uuid4() به صورت داخلی os.urandom(16) را فراخوانی می‌کند، سپس بیت‌های ۶–۷ از بایت ۸ را به 10 (variant) و بیت‌های ۱۲–۱۵ از بایت ۶ را به 0100 (نسخه ۴) تنظیم می‌کند. ۱۲۲ بیت باقی‌مانده تصادفی هستند. به همین دلیل است که نمی‌توان به نسخه اعتماد کرد مگر اینکه با uuid.UUID() تجزیه کنید.

ویژگی‌ها و نمایش‌های شیء UUID

شیء uuid.UUID چندین نمایش از همان مقدار ۱۲۸ بیتی را ارائه می‌دهد. انتخاب مناسب برای لایه ذخیره‌سازی از خراب شدن بی‌صدا داده و بایت‌های هدررفته جلوگیری می‌کند.

ویژگی / متد
نوع
توضیح
uuid.UUID(hex=...)
UUID
تجزیه یک UUID موجود از رشته hex، با یا بدون خط تیره.
.hex
str
رشته hex کوچک ۳۲ کاراکتری بدون خط تیره — فرمت فشرده برای ذخیره‌سازی.
.int
int
نمایش عدد صحیح ۱۲۸ بیتی UUID — مفید برای عملیات حسابی و مرتب‌سازی.
.bytes
bytes
نمایش باینری ۱۶ بایتی big-endian — کوچک‌ترین اندازه ذخیره‌سازی.
.bytes_le
bytes
باینری ۱۶ بایتی little-endian — مطابق ترتیب بایت Microsoft GUID.
.fields
tuple
تاپل شش‌عنصری فیلدهای UUID: (time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node).
.version
int | None
شماره نسخه UUID (۱ تا ۵، یا None برای UUID‌های غیراستاندارد).
.variant
str
رشته variant UUID — "specified in RFC 4122" برای UUID‌های استاندارد.
str(uuid_obj)
str
رشته کانونیکال ۳۶ کاراکتری با چهار خط تیره: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
Python 3.8+ — تمام نمایش‌ها
import uuid

u = uuid.uuid4()

print(str(u))         # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"  (۳۶ کاراکتر)
print(u.hex)          # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"      (۳۲ کاراکتر، بدون خط تیره)
print(u.bytes)        # b';Š...'                       (۱۶ بایت، big-endian)
print(u.bytes_le)     # b'Š...'                       (۱۶ بایت، little-endian)
print(u.int)          # 78823... (عدد صحیح ۱۲۸ بیتی)
print(u.version)      # 4
print(u.variant)      # 'specified in RFC 4122'

# رفت و برگشت: بازسازی از رشته
reconstructed = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
print(reconstructed == u)  # True (اگر u آن مقدار باشد)

برای PostgreSQL با psycopg2 یا asyncpg، شیء UUID را مستقیماً پاس دهید — درایور mapping به نوع ستون بومی uuid را مدیریت می‌کند. برای SQLite از str(u) (TEXT) یا u.bytes (BLOB، ۱۶ بایت در مقابل ۳۶ بایت برای رشته) استفاده کنید. برای کارایی ذخیره‌سازی در مقیاس، .bytes نسبت به رشته کانونیکال ۵۵٪ کوچک‌تر است.

اعتبارسنجی و تجزیه رشته‌های UUID v4 در Python

هر زمان که یک UUID از ورودی کاربر، پارامتر مسیر URL، یا یک API بالادست می‌رسد، باید قبل از استفاده به عنوان کلید پایگاه داده آن را اعتبارسنجی کنید. رویکرد اصولی تلاش برای ساخت با uuid.UUID() و catch کردن ValueError است. همچنین می‌توانید با بررسی .version اطمینان حاصل کنید که مقدار ورودی خصوصاً نسخه ۴ است.

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"فرمت UUID نامعتبر: {raw!r}") from exc

    if u.version != 4:
        raise ValueError(f"UUID v4 انتظار داشت، v{u.version} دریافت شد: {raw!r}")

    return u

# استفاده در یک route handler از FastAPI / Flask
def get_order(order_id: str):
    try:
        uid = parse_uuid4(order_id)
    except ValueError as exc:
        return {"error": str(exc)}, 400

    # uid را می‌توان با اطمینان در یک کوئری DB استفاده کرد
    return {"order_id": str(uid), "status": "processing"}
یادداشت:uuid.UUID() رشته‌هایی با یا بدون خط تیره را می‌پذیرد، و همچنین پیشوند urn:uuid: را قبول می‌کند. بنابراین "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" (بدون خط تیره) و "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" هر دو به همان شیء تجزیه می‌شوند.

سریال‌سازی اشیاء UUID در JSON — default= و JSONEncoder سفارشی

استاندارد JSON نوع UUID ندارد — یک UUID در JSON همیشه یک رشته است. این به این معناست که باید شیء uuid.UUID را قبل از پاس دادن به json.dumps() به رشته تبدیل کنید. تمیزترین رویکرد یک زیرکلاس سفارشی JSONEncoder است تا هرگز مجبور نشوید فراخوانی‌های str() را در سراسر کدبیس پراکنده کنید.

Python 3.8+ — JSONEncoder سفارشی برای UUID
import json
import uuid
from datetime import datetime

class ApiEncoder(json.JSONEncoder):
    """اشیاء UUID و datetime را در پاسخ‌های JSON سریال‌سازی کنید."""
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return str(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

# پاسخ API واقعی با 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-...",
#     ...
#   }
# }
هشدار:اگر نوعی در default() مدیریت نشد، باید super().default(obj) را فراخوانی کنید تا یک TypeError با پیام مناسب ایجاد شود — در غیر این صورت سریال‌ساز به صورت بی‌صدا None برمی‌گرداند و داده شما خاموش از دست می‌رود.

برای یک فراخوانی سریال‌سازی یک‌باره، hook default= ساده‌تر از زیرکلاس‌سازی است:

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"}

UUID v4 در payload‌های JSON و پاسخ‌های API

هنگام دریافت پاسخ از یک API خارجی، رشته‌های UUID را دوباره به اشیاء تجزیه کنید تا کدتان مجموعه ویژگی کامل و type safety را داشته باشد:

Python 3.8+ — تجزیه UUID از پاسخ API
import json
import uuid
import requests

def fetch_shipment(shipment_id: str) -> dict:
    """یک shipment را دریافت کرده و با فیلدهای 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"پاسخ shipment ناقص: {exc}") from exc

    return data

برای به‌روزرسانی فیلدهای UUID در یک فایل JSON روی دیسک — برای مثال، چرخش یک correlation ID در یک فایل config یا seed — بخوانید، تغییر دهید و به صورت اتمی بنویسید:

Python 3.8+ — خواندن، به‌روزرسانی و نوشتن فایل JSON
import json, uuid

def rotate_correlation_id(path: str) -> str:
    """'correlation_id' را در یک فایل JSON جایگزین یا اضافه کنید. UUID جدید را برمی‌گرداند."""
    try:
        with open(path) as f:
            data = json.load(f)
    except FileNotFoundError:
        data = {}
    except json.JSONDecodeError as exc:
        raise ValueError(f"JSON نامعتبر در {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 دارید اسکریپت اجرا کنید، آن را مستقیماً در UUID Decoder جایگذاری کنید — نسخه، variant و همه فیلدها را بدون هیچ کدی نشان می‌دهد.

تولید UUID v4 از خط فرمان با Python

ماژول uuid Python یک زیرفرمان CLI مستقل مانند python -m json.tool ارائه نمی‌دهد، اما یک one-liner همان کاربرد را پوشش می‌دهد. اینها در اسکریپت‌های shell، pipeline‌های CI، و هر زمان که بدون باز کردن یک REPL به یک شناسه موقت نیاز دارید مفید هستند.

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

# فرمت بدون خط تیره (hex) — مفید برای نام فایل‌ها و env var‌ها
python3 -c "import uuid; print(uuid.uuid4().hex)"
# 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e

# تولید ۵ UUID برای یک اسکریپت seed دسته‌ای
python3 -c "import uuid; [print(uuid.uuid4()) for _ in range(5)]"

# استفاده در یک متغیر shell
DEPLOY_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
echo "استقرار با ID: $DEPLOY_ID"
یادداشت:در macOS و اکثر توزیع‌های Linux، uuidgen (یک ابزار C) مقادیر UUID v4 تولید می‌کند و برای اسکریپت‌های pure shell سریع‌تر است. از one-liner Python زمانی استفاده کنید که قبلاً در یک محیط Python-محور هستید و می‌خواهید با نحوه تولید UUID در کد اپلیکیشن‌تان همگون باشید.

UUID v4 با کارایی بالا با uuid-utils

uuid.uuid4() کتابخانه استاندارد برای اکثر اپلیکیشن‌ها به اندازه کافی سریع است — با چند میکروثانیه در هر فراخوانی، هزاران ID در ثانیه را به راحتی مدیریت می‌کند. اگر UUID‌ها را در مسیر hot یک سرویس با توان عملیاتی بالا تولید می‌کنید (درج‌های انبوه، telemetry per-event در مقیاس، یا تولید request ID تحت بار سنگین), uuid-utils یک جایگزین drop-in با پشتیبانی Rust است که در benchmark‌ها تقریباً ۱۰ برابر سریع‌تر از stdlib است.

bash — نصب
pip install uuid-utils
Python 3.8+ — جایگزین drop-in uuid-utils
# uuid_utils یک جایگزین drop-in برای ماژول stdlib uuid است
import uuid_utils as uuid

# همان API stdlib
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 نیز پشتیبانی می‌کند (مرتب‌شده بر اساس زمان، عالی برای کلیدهای اصلی DB)
time_ordered_id = uuid.uuid7()
print(time_ordered_id)      # با پیشوند timestamp فعلی شروع می‌شود
هشدار:حالت پیش‌فرض uuid-utils نوع شیء UUID خود را برمی‌گرداند که در اکثر موارد با stdlib سازگار است. اگر به بررسی‌های دقیق isinstance(u, uuid.UUID) از کتابخانه استاندارد نیاز دارید، از حالت compat استفاده کنید: import uuid_utils.compat as uuid. حالت compat کمی کندتر از حالت پیش‌فرض است اما هنوز سریع‌تر از stdlib است.

UUID v4 در Dataclass‌ها و مدل‌های Pydantic

Dataclass‌های Python و مدل‌های Pydantic هر دو از فیلدهای UUID به صورت بومی پشتیبانی می‌کنند. الگوی کلیدی هنگام استفاده از UUID به عنوان پیش‌فرض خودکار تولیدشده، پاس دادن رفرنس تابعاست، نه نتیجه فراخوانی — در غیر این صورت هر instance همان UUID را به اشتراک می‌گذارد.

Python 3.10+ — dataclass با پیش‌فرض UUID
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)  # یکتا برای هر instance
print(job2.job_id)  # متفاوت از job1.job_id
print(job1.job_id == job2.job_id)  # False
Python 3.10+ — مدل Pydantic v2 با 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 uuid.UUID را به صورت خودکار به رشته تبدیل می‌کند

اشتباهات رایج هنگام تولید UUID v4 در Python

همه چهار این الگو را در code review‌ها و حوادث production دیده‌ام — به راحتی از دست می‌روند چون بلافاصله خطا ایجاد نمی‌کنند.

فراخوانی uuid4 بدون پرانتز به عنوان مقدار پیش‌فرض

مشکل: پاس دادن uuid.uuid4 (شیء تابع) به عنوان مقدار پیش‌فرض در یک dataclass یا مدل بدون wrap کردن آن در default_factory — Python پیش‌فرض را یک بار در زمان تعریف کلاس ارزیابی می‌کند، بنابراین هر instance همان UUID را به اشتراک می‌گذارد.

راه‌حل: در dataclass‌ها از default_factory=uuid.uuid4 یا در Pydantic از Field(default_factory=uuid.uuid4) استفاده کنید تا یک UUID تازه برای هر instance تولید شود.

After · Python
Before · Python
@dataclass
class Session:
    # درست: factory برای هر instance فراخوانی می‌شود
    session_id: uuid.UUID = field(default_factory=uuid.uuid4)
@dataclass
class Session:
    # اشتباه: یک بار ارزیابی می‌شود، همه instance‌ها این UUID را به اشتراک می‌گذارند
    session_id: uuid.UUID = uuid.uuid4()
مقایسه شیء UUID با یک رشته ساده

مشکل: اشیاء uuid.UUID با رشته‌های ساده برابر نیستند، بنابراین session_id == '3b1f8a9d-...' همیشه False برمی‌گرداند حتی وقتی مقدار مطابقت دارد — جستجوها را به صورت بی‌صدا خراب می‌کند.

راه‌حل: همیشه UUID را با UUID مقایسه کنید: رشته را با uuid.UUID() wrap کنید قبل از مقایسه، یا هر دو طرف را با str() تبدیل کنید.

After · Python
Before · Python
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)
# حتی وقتی مقادیر برابرند False برمی‌گرداند
if record["session_id"] == "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e":
    revoke_session(record)
ذخیره .hex به جای str() و از دست دادن خط تیره‌ها

مشکل: uuid_obj.hex یک رشته ۳۲ کاراکتری بدون خط تیره تولید می‌کند. اگر کد downstream فرمت ۳۶ کاراکتری کانونیکال با خط تیره انتظار داشته باشد (اکثر API‌ها و پایگاه‌های داده این‌گونه هستند)، آن را رد خواهد کرد یا به صورت بی‌صدا آن را اشتباه تجزیه خواهد کرد.

راه‌حل: از str(uuid_obj) برای فرمت ۳۶ کاراکتری کانونیکال استفاده کنید مگر اینکه نیاز صریح به فرمت hex فشرده داشته باشید.

After · Python
Before · Python
# ذخیره "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" — فرمت استاندارد
payload = {"correlation_id": str(request_id)}
# ذخیره "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" — بدون خط تیره
payload = {"correlation_id": request_id.hex}
استفاده از random.random() یا secrets.token_hex() وقتی UUID انتظار می‌رود

مشکل: random.random() از نظر رمزنگاری امن نیست، و secrets.token_hex(16) یک رشته hex ۳۲ کاراکتری تولید می‌کند که یک UUID معتبر نیست — اعتبارسنج‌های downstream که uuid.UUID() را روی آن فراخوانی می‌کنند ValueError ایجاد خواهند کرد.

راه‌حل: از uuid.uuid4() استفاده کنید هر زمان که سیستم دریافت‌کننده انتظار یک شناسه با فرمت UUID دارد. از secrets.token_hex() فقط زمانی استفاده کنید که صریحاً به یک توکن تصادفی غیر UUID-shaped نیاز دارید.

After · Python
Before · Python
import uuid

request_id = str(uuid.uuid4())  # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
# UUID v4 معتبر، امن از نظر رمزنگاری
import random, secrets

# UUID نیست — اعتبارسنجی uuid.UUID() شکست خواهد خورد
request_id = secrets.token_hex(16)   # "a1b2c3d4e5f6..."
session_id = str(random.random())    # "0.8273..." — اصلاً نزدیک هم نیست

روش‌های تولید UUID در Python — مقایسه سریع

همه روش‌های زیر شناسه‌های ۱۲۸ بیتی تولید می‌کنند اما از نظر منبع entropy، ویژگی‌های حریم خصوصی، و اینکه آیا نصب third-party نیاز دارند متفاوت هستند.

متد
منبع
یکتایی
حفظ حریم خصوصی
نوع سفارشی
سرعت
نصب
uuid.uuid4()
تصادفی (os.urandom)
۲¹²² بیت تصادفی
ندارد
استاندارد
داخلی
uuid.uuid1()
Timestamp + MAC
زمان + هاست
❌ (MAC افشا می‌شود)
ندارد
استاندارد
داخلی
uuid.uuid3(name)
هش MD5
قطعی
namespace+name
استاندارد
داخلی
uuid.uuid5(name)
هش SHA-1
قطعی
namespace+name
استاندارد
داخلی
uuid_utils.uuid4()
Rust os.urandom
۲¹²² بیت تصادفی
ندارد
~۱۰× سریع‌تر
pip install uuid-utils
secrets.token_hex(16)
os.urandom
۱۲۸ بیت تصادفی
ندارد
سریع
داخلی
str(uuid.uuid4())
تصادفی
۲¹²² بیت تصادفی
ندارد
استاندارد
داخلی

از uuid.uuid4() برای شناسه‌های یکتای عمومی در اپلیکیشن‌های وب، سیستم‌های توزیع‌شده، و کلیدهای اصلی پایگاه داده زمانی که مرتب‌پذیری نیاز نیست استفاده کنید. از uuid.uuid5() (یا v3) برای ID‌های قطعی مشتق‌شده از یک namespace و name شناخته‌شده استفاده کنید — برای مثال، تولید یک ID ثابت برای یک URL کانونیکال. به uuid_utils.uuid7() سوئیچ کنید وقتی به ID‌های مرتب‌شده بر اساس زمان برای ایندکس‌های پایگاه داده نیاز دارید (از page split‌ها در ایندکس‌های B-tree با نرخ درج بالا جلوگیری می‌کند). از uuid_utils.uuid4() استفاده کنید وقتی throughput تولید خام، گلوگاه است.

UUID v4 در مقابل UUID v7 — کدام را باید استفاده کنید؟

رایج‌ترین سوال عملی این است که آیا از UUID v4 یا UUID v7 جدیدتر برای کلیدهای اصلی پایگاه داده استفاده کنید. پاسخ کوتاه: به‌طور پیش‌فرض از UUID v4 استفاده کنید؛ فقط زمانی به UUID v7 سوئیچ کنید که تکه‌تکه‌شدن ایندکس یک مشکل اندازه‌گیری‌شده باشد.

مقادیر UUID v4 کاملاً تصادفی هستند، به این معنا که درج‌ها در موقعیت‌های تصادفی در یک ایندکس B-tree فرود می‌آیند. در نرخ‌های درج متوسط (صدها تا هزارهای پایین در ثانیه) این مشکلی نیست — ایندکس در buffer pool جا می‌شود و نوشتن‌های تصادفی ارزان هستند. در نرخ‌های درج بسیار بالا، قرارگیری تصادفی باعث page split‌های مکرر و cache miss می‌شود که write amplification را افزایش می‌دهد و کوئری‌ها را کند می‌کند.

UUID v7 یک timestamp Unix با دقت میلی‌ثانیه را در مهم‌ترین بیت‌ها جاسازی می‌کند، بنابراین ردیف‌های درج‌شده در نزدیکی هم از نظر زمانی نیز در ایندکس نزدیک هم قرار می‌گیرند. این رفتار ایندکس‌های B-tree (PostgreSQL، MySQL، SQLite) را نزدیک‌تر به یک عدد صحیح auto-increment می‌کند: ردیف‌های جدید همیشه به انتهای ایندکس اضافه می‌شوند و page split‌ها را حذف می‌کنند. معادله این است که UUID v7 یک timestamp را کدگذاری می‌کند که زمان ایجاد را افشا می‌کند — برای ID‌های رو به کاربر که زمان ایجاد حساس است از آن اجتناب کنید.

در Python، UUID v7 هنوز در کتابخانه استاندارد نیست (تا Python 3.12). آن را با pip install uuid-utils نصب کنید و uuid_utils.uuid7() را فراخوانی کنید. این یک شیء با همان مجموعه ویژگی uuid.UUID برمی‌گرداند، بنابراین مهاجرت از v4 یک تغییر یک‌خطی در factory ID است.

برای یک جایگزین یک‌کلیکی بدون هیچ راه‌اندازی Python، رشته UUID خود را در مولد و اعتبارسنج UUID v4 جایگذاری کنید — تمام فیلدها را در مرورگر تولید، اعتبارسنجی و decode می‌کند.

سوالات متداول

چگونه UUID v4 در Python تولید کنم؟

تابع uuid.uuid4() را از ماژول داخلی uuid فراخوانی کنید. این تابع یک شیء UUID برمی‌گرداند — برای نمایش متنی با str() آن را تبدیل کنید. این ماژول بخشی از کتابخانه استاندارد است و نیاز به نصب pip ندارد.

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()) آن شیء را فوراً به رشته کانونیکال ۳۶ کاراکتری تبدیل می‌کند و شیء را دور می‌اندازد. اگر به چندین نمایش نیاز دارید شیء را نگه دارید؛ در مرز ارسال به payload JSON، پایگاه داده یا هدر HTTP آن را به رشته تبدیل کنید.

Python
import uuid

u = uuid.uuid4()
print(type(u))          # <class 'uuid.UUID'>
print(u.version)        # 4
print(u.hex)            # هگز ۳۲ کاراکتری، بدون خط تیره
print(u.bytes)          # باینری ۱۶ بایتی
print(str(u))           # رشته کانونیکال ۳۶ کاراکتری با خط تیره

آیا uuid.uuid4() از نظر رمزنگاری امن است؟

بله. uuid.uuid4() در Python به صورت داخلی از os.urandom() استفاده می‌کند که از مولد اعداد تصادفی امن سیستم‌عامل می‌خواند (/dev/urandom در Linux/macOS، CryptGenRandom در Windows). ۱۲۲ بیت تصادفی احتمال تصادف را برای هر بار کار واقع‌بینانه ناچیز می‌کند. آن را با random.random() اشتباه نگیرید که از نظر رمزنگاری امن نیست.

Python
import uuid, os

# uuid4 به صورت داخلی os.urandom(16) را فراخوانی می‌کند
raw = os.urandom(16)
# uuid4 بیت‌های version و variant را قبل از return تنظیم می‌کند
u = uuid.UUID(bytes=raw, version=4)
print(u)  # UUID v4 معتبر از بایت‌های تصادفی خام

چگونه اعتبار یک رشته UUID v4 را در Python بررسی کنم؟

با uuid.UUID() تجزیه کنید و ویژگی .version را بررسی کنید. اگر رشته یک UUID معتبر نباشد، uuid.UUID() یک ValueError ایجاد می‌کند — برای مدیریت ورودی نامعتبر آن را catch کنید. این همچنین فرمت (خط تیره، طول) را اعتبارسنجی می‌کند.

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)

چگونه UUID‌ها را در پایگاه داده PostgreSQL یا SQLite از Python ذخیره کنم؟

با PostgreSQL (از طریق psycopg2 یا asyncpg)، شیء UUID را مستقیماً پاس دهید — درایور آن را به نوع UUID بومی تبدیل می‌کند. با SQLite که نوع UUID بومی ندارد، به صورت 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()
# UUID object را از رشته ذخیره‌شده بازسازی کنید
retrieved_id = uuid.UUID(row[0])
print(retrieved_id.version)  # 4

آیا می‌توانم چندین UUID را به صورت هم‌زمان در Python تولید کنم؟

بله — از list comprehension یا generator استفاده کنید. هر فراخوانی uuid.uuid4() مستقل است و یک مقدار متمایز تضمین‌شده تولید می‌کند. برای تولید انبوه که توان عملیاتی اهمیت دارد، uuid-utils (با پشتیبانی Rust) حدود ۱۰ برابر سریع‌تر از کتابخانه استاندارد است.

Python
import uuid

# ۵ trace 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 را بررسی کنید — نسخه، variant، timestamp (v1/v7)، و فیلدهای node — بدون نوشتن یک parser از صفر.
  • JWT Decoderتوکن‌های JWT را decode و بررسی کنید که اغلب UUID‌های subject (sub) یا شناسه‌های jti را همراه با UUID‌های session حمل می‌کنند.
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.