سطح مقدماتی (Beginner Level)
در نسخههای قدیمیتر پایتون، ایجاد کلاسهایی که تنها وظیفه نگهداری دادهها را داشتند، نیازمند نوشتن کدهای تکراری (Boilerplate) زیادی مانند __init__، __repr__ و __eq__ بود. ماژول dataclasses که در پایتون ۳.۷ معرفی شد، این فرآیند را خودکار و بسیار ساده میکند.
۱. دیتاکلس چیست و چرا از آن استفاده کنیم؟
دیتاکلس یک دکوریتور (Decorator) به نام @dataclass است که وقتی به یک کلاس اضافه میشود، به صورت خودکار متدهای خاصی را برای آن تولید میکند.
مزایا:
- کد کمتر و خواناتر.
- تولید خودکار متد
__init__برای مقداردهی اولیه. - تولید خودکار
__repr__برای نمایش زیبای آبجکت. - پشتیبانی از Type Hinting.
مثال اول: ساختار کلاسیک در برابر دیتاکلس
در اینجا میبینید که چگونه دیتاکلس نیاز به تعریف دستی __init__ را از بین میبرد.
مثال دوم: مقایسه با کلاس معمولی (Static)
این کد صرفاً برای مقایسه ساختار است و نیازی به اجرا ندارد.
# Example 2: How it would look WITHOUT dataclasses (Static Snippet)
class PointOld:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def __repr__(self):
return f"PointOld(x={self.x}, y={self.y})"
۲. مقادیر پیشفرض (Default Values)
شما میتوانید برای فیلدهای خود مقادیر پیشفرض تعیین کنید. دقیقاً مانند آرگومانهای توابع، فیلدهای دارای مقدار پیشفرض باید بعد از فیلدهای بدون مقدار پیشفرض قرار گیرند.
مثال اول: تعریف محصول با قیمت پیشفرض
مثال دوم: قوانین ترتیب فیلدها (Static)
این قطعه کد نشاندهنده یک قانون نحوی (Syntax Rule) است.
# Example 2: Syntax rule (Correct ordering)
@dataclass
class User:
id: int # بدون مقدار پیشفرض (اول میآید)
is_active: bool = True # با مقدار پیشفرض (بعد میآید)
۳. برابری و مقایسه (Equality & Comparison)
یکی از ویژگیهای قدرتمند دیتاکلسها، پیادهسازی خودکار __eq__ است. دو نمونه از یک دیتاکلس اگر مقادیر فیلدهایشان یکسان باشد، برابر در نظر گرفته میشوند.
مثال اول: مقایسه دو آبجکت
مثال دوم: تعریف متدها در دیتاکلس
شما همچنان میتوانید متدهای خود را به کلاس اضافه کنید.
سطح پیشرفته (Professional Level)
در سطح حرفهای، ماژول dataclasses امکانات بسیار قدرتمندی برای کنترل دقیق رفتار کلاس، مدیریت حافظه، و کار با دادههای تغییرپذیر (Mutable) ارائه میدهد.
۱. مدیریت لیستها و دیکشنریها (default_factory)
یکی از اشتباهات رایج در پایتون، استفاده از لیست یا دیکشنری خالی [] به عنوان مقدار پیشفرض است. در دیتاکلسها، پایتون اجازه این کار را نمیدهد و شما باید از field(default_factory=...) استفاده کنید تا برای هر نمونه یک لیست جدید ساخته شود.
مثال اول: استفاده صحیح از default_factory
مثال دوم: سناریوی خطا (Static)
کد زیر نشان میدهد چه چیزی ممنوع است.
# Example 2: This will raise a ValueError (Static explanation)
from dataclasses import dataclass
@dataclass
class Wrong:
# این خط باعث خطا میشود چون لیست mutable است
items: list = []
۲. پردازش پس از مقداردهی (post_init)
گاهی اوقات نیاز دارید که مقدار یک فیلد را بر اساس سایر فیلدها محاسبه کنید یا اعتبارسنجی (Validation) انجام دهید. متد __post_init__ بلافاصله پس از __init__ اجرا میشود.
مثال اول: محاسبه فیلد مشتق شده
مثال دوم: اعتبارسنجی دادهها
۳. کلاسهای تغییرناپذیر (Frozen Dataclasses)
برای ساخت آبجکتهایی که پس از ایجاد نباید تغییر کنند (Immutable)، میتوانید از پارامتر frozen=True استفاده کنید. این کار باعث میشود کلاس قابلیت Hash شدن پیدا کند و بتوان از آن به عنوان کلید دیکشنری استفاده کرد.
مثال اول: تلاش برای تغییر مقدار
مثال دوم: استفاده به عنوان کلید دیکشنری
۴. پیکربندی پیشرفته فیلدها (Field Configuration)
تابع field() امکانات کنترلی زیادی دارد. مثلاً میتوانید تعیین کنید که یک فیلد در __repr__ نمایش داده نشود (مانند رمز عبور) یا در مقایسهها شرکت نکند.
مثال اول: مخفی کردن اطلاعات حساس
مثال دوم: فیلدهای فقط کلیدواژهای (Keyword-Only)
در پایتون ۳.۱۰+ میتوانید با kw_only=True کاربر را مجبور کنید نام آرگومانها را بنویسد.
# Example 2: Keyword-only syntax (Static)
@dataclass(kw_only=True)
class APIConfig:
endpoint: str
timeout: int
# Valid: APIConfig(endpoint="...", timeout=5)
# Invalid: APIConfig("...", 5)
۵. بهینهسازی حافظه با Slots
به طور پیشفرض، کلاسها در پایتون دادهها را در یک دیکشنری (__dict__) ذخیره میکنند که حافظه زیادی مصرف میکند. با استفاده از slots=True (پایتون ۳.۱۰+)، کلاس به جای دیکشنری از ساختار حافظه ثابت استفاده میکند که دسترسی سریعتر و مصرف رم کمتری دارد.
مثال اول: بررسی وجود slots
مثال دوم: محدودیتهای Slots (Static)
وقتی از slots استفاده میکنید، نمیتوانید ویژگیهای جدیدی که تعریف نشدهاند را به آبجکت اضافه کنید.
# Example 2: Limitation of slots (Static Logic)
# p = OptimizedPoint(1, 2)
# p.z = 3 # AttributeError: 'OptimizedPoint' object has no attribute 'z'