ویژگی تصویر

معرفی کتابخانه dataclasses در پایتون

  /  پایتون   /  کتابخانه dataclasses در پایتون
بنر تبلیغاتی الف

کتابخانه dataclasses که از پایتون 3.7 به‌طور رسمی اضافه شد، برای تعریف کلاس‌هایی طراحی شده که عمدتاً نگهدارنده داده (data containers) هستند. با استفاده از دکوراتور @dataclass می‌توان کد تکراری مثل سازنده (__init__)، نمایشی خواندنی (__repr__)، و توابع مقایسه را به‌صورت خودکار تولید کرد. این کتابخانه ساده، خوانایی و سرعت توسعه را افزایش می‌دهد و در کاربردهای مثل DTOها، پیکربندی‌ها و سریال‌سازی بسیار مفید است.

مثال ساده

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int = 0
    active: bool = True

p = Person("Ali", 30)
print(p)  # Person(name='Ali', age=30, active=True)

در این مثال، @dataclass به‌صورت خودکار متد __init__ و __repr__ و __eq__ را می‌سازد. این کار باعث می‌شود کد خواناتر و کوتاه‌تر باشد.

پارامترهای مهم دکوراتور

پارامترتوضیحمقدار پیش‌فرض
initتولید __init__ یا خیرTrue
reprتولید __repr__True
eqتولید __eq__ برای مقایسهٔ اشیاءTrue
orderتولید متدهای مرتب‌سازی (__lt__, __gt__, …)False
frozenایمن‌سازی داده — غیرقابل تغییر کردن نمونهFalse
slotsاستفاده از __slots__ برای کاهش حافظه و افزایش سرعتFalse (Python ≥ 3.10)

پیش‌فرض‌های قابل اشتباه: default_factory و داده‌های قابل تغییر

from dataclasses import dataclass, field
from typing import List

@dataclass
class Team:
    name: str
    members: List[str] = field(default_factory=list)

t1 = Team("A")
t1.members.append("Ali")
t2 = Team("B")
print(t2.members)  # [] — safe because default_factory ساخته می‌شود

استفاده از لیست یا دیکشنری به‌عنوان مقدار پیش‌فرض مستقیم اشتباه است چون یک شیء مشترک بین همهٔ نمونه‌ها می‌شود. برای جلوگیری از این مشکل از field(default_factory=...) استفاده کنید تا هر نمونه یک شیء جدید بگیرد.

مثال: کلاس‌های ایمن (frozen) و ایجاد نسخهٔ جدید

from dataclasses import dataclass, replace

@dataclass(frozen=True)
class Config:
    host: str
    port: int

c1 = Config("localhost", 8000)
# c1.port = 8080  # خطا: تغییر در dataclass منجمد امکان‌پذیر نیست
c2 = replace(c1, port=8080)
print(c1, c2)

با frozen=True نمونه‌ها غیرقابل تغییر می‌شوند. برای ساختن نسخه‌ای جدید با اندکی تغییر، از تابع replace استفاده می‌کنیم که یک شیء جدید با مقادیر جایگزین شده برمی‌گرداند.

اعتبارسنجی بعد از مقداردهی: __post_init__

from dataclasses import dataclass

@dataclass
class Product:
    name: str
    price: float

    def __post_init__(self):
        if self.price < 0:
            raise ValueError("price must be non-negative")

متد __post_init__ بلافاصله بعد از ساخت نمونه و اجرای __init__ اجرا می‌شود. برای اعتبارسنجی، تبدیل داده‌ها یا مقداردهی مشتق‌ شده از این متد استفاده کنید.

سریال‌سازی سریع: asdict و astuple

from dataclasses import asdict, astuple

p = Person("Sara", 25)
print(asdict(p))   # {'name': 'Sara', 'age': 25, 'active': True}
print(astuple(p))  # ('Sara', 25, True)

توابع asdict و astuple به‌سرعت یک نمونهٔ dataclass را به دیکشنری یا تاپل تبدیل می‌کنند که برای سریال‌سازی یا لاگ‌گیری مفید است. توجه داشته باشید که این توابع به‌صورت بازگشتی برای dataclassهای تو در تو عمل می‌کنند.

ویژگی های پیشرفته و کاربردهای عملی

  • slots=True (از پایتون 3.10): کاهش حافظه و سرعت دسترسی بهتر برای تعداد زیاد نمونه‌ها.
  • order=True: اضافه کردن مرتب‌سازی طبیعی بر اساس ترتیب فیلدها.
  • استفاده در DTO، خواندن/نوشتن کانفیگ، تبدیل به JSON و تعامل با فریم‌ورک‌هایی مثل FastAPI یا کتابخانه‌های سریال‌سازی.
  • ترکیب با typing برای گرفتن مزایای نوع‌دهی استاتیک و تکمیل اتوماتیک در IDEها.

نمونه: استفادهٔ بهینه با slots و typing

from dataclasses import dataclass
from typing import List

@dataclass(slots=True)
class Point:
    x: float
    y: float

@dataclass(slots=True)
class Polygon:
    vertices: List[Point]

استفاده از slots=True می‌تواند مصرف حافظه را کم کند و سرعت دسترسی به attributes را افزایش دهد. این گزینه برای ساختارهایی با هزاران نمونه بسیار مفید است. توجه کنید که پشتیبانی کامل slots از پایتون 3.10 به بعد بهتر است.

بهترین شیوه‌ها و نکات نهایی

  • برای مقادیر پیش‌فرض قابل تغییر از field(default_factory=...) استفاده کنید.
  • اگر می‌خواهید اشیاءimmutable باشند، از frozen=True بهره ببرید و برای تغییرات از replace استفاده کنید.
  • در برنامه‌های حجیم با تعداد زیاد نمونه، slots=True را بررسی کنید تا مصرف حافظه کاهش یابد.
  • برای اعتبارسنجی یا تبدیل‌های پس از مقداردهی از __post_init__ استفاده کنید.
  • اگر نیاز به کنترل دقیق‌تری روی سریال‌سازی/ولید دارید، dataclasses را با کتابخانه‌هایی مثل marshmallow یا pydantic مقایسه کنید؛ dataclasses ساده، سبک و مناسب برای بیشتر نیازهاست.

کتابخانهٔ dataclasses راهی ساده و قدرتمند برای مدیریت کلاس‌های نگهدارندهٔ داده در پایتون فراهم می‌کند. با رعایت چند قاعدهٔ ساده (استفاده از default_factory برای داده‌های قابل تغییر، به‌کارگیری frozen برای ایمنی، و در صورت نیاز فعال‌سازی slots) می‌توانید کدی تمیزتر، سریع‌تر و ایمن‌تر بنویسید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: