آموزش پایتون - دیتاکلاس

ویژگی dataclass یکی از قابلیت‌های پایتون است که به افزودن خودکار متدهای ویژه به کلاس‌های تعریف‌شده توسط کاربر کمک می‌کند. به عنوان مثال، یک dataclass می‌تواند برای تولید خودکار متد سازنده (constructor) برای کلاس شما استفاده شود تا بتوانید به راحتی نمونه‌هایی از کلاس بسازید. در این فصل، تمام ویژگی‌های ماژول dataclass را با کمک مثال‌ها توضیح خواهیم داد.

دیتاکلاس (Dataclass) چیست؟

یک dataclass در واقع یک کلاس پایتون است که با دکوراتور dataclass@ از ماژول dataclasses مشخص می‌شود. از آن برای تولید خودکار متدهای ویژه مانند متد سازنده ()init__repr__، متد نمایش رشته‌ای ()__repr__، متد برابری ()eq__ و موارد دیگر بر اساس ویژگی‌های کلاس (class attributes) تعریف‌شده در بدنه کلاس استفاده می‌شود. این به زبان ساده یعنی استفاده از dataclassها می‌تواند کد‌های تکراری (boilerplate) را در تعریف کلاس‌های شما کاهش دهد.

سنتکس Dataclass

سنتکس تعریف یک dataclass به صورت زیر است −

@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)

هر آرگومان یک مقدار بولین (boolean) می‌گیرد که مشخص می‌کند آیا متدهای ویژه مربوطه باید به طور خودکار تولید شوند یا خیر.

دکوراتور dataclass@ می‌تواند این گزینه‌ها را دریافت کند:

  • init (پیش‌فرض: True) − به طور خودکار یک متد ()init__ برای مقداردهی اولیه نمونه‌های کلاس ایجاد می‌کند.
  • repr (پیش‌فرض: True) − به طور خودکار یک متد ()repr__ برای ارائه یک نمایش رشته‌ای خوانا از شئ ایجاد می‌کند.
  • eq (پیش‌فرض: True) − یک متد ()eq__ برای مقایسه اشیاء با استفاده از عملگر == تولید می‌کند.
  • order (پیش‌فرض: False) − اگر روی True تنظیم شود، متدهای مقایسه (مانند < و >) برای مرتب‌سازی اشیاء تولید می‌شوند.
  • unsafe_hash (پیش‌فرض: False) − اگر false باشد، یک متد ()hash__ پیش‌فرض بر اساس نحوه تعریف برابری و تغییرپذیری ایجاد می‌کند.
  • frozen (پیش‌فرض: False) − نمونه‌های تغییرناپذیر (immutable) ایجاد می‌کند (پس از ایجاد قابل تغییر نیستند).

ایجاد یک Dataclass

در کد زیر می‌توانید ببینید که ما یک dataclass ساده به نام Student با سه ویژگی تعریف کرده‌ایم: name، age و percent. اگرچه ما از سازنده یا سایر متدهای ویژه استفاده نمی‌کنیم، اما همچنان می‌توانیم نمونه‌هایی از کلاس Student ایجاد کرده و از ویژگی‌های آن استفاده کنیم. این به این دلیل است که دکوراتور dataclass به طور خودکار این متدها را برای ما تولید می‌کند.

from dataclasses import dataclass  

@dataclass  
class Student:  
    name: str  
    age: int  
    percent: float

s1 = Student("Alice", 20, 90.0)
s2 = Student("Bob", 22, 85.5)

print(s1)         
print(s1 == s2)   

خروجی کد بالا به صورت زیر خواهد بود −

Student(name='Alice', age=20, percent=90.0)
False

مثال بدون استفاده از Dataclass

کد بالا معادل کد زیر در تعریف کلاس سنتی بدون استفاده از dataclass است −

class Student:  
    def __init__(self, name: str, age: int, percent: float):  
        self.name = name  
        self.age = age  
        self.percent = percent  
    def __repr__(self):  
        return f"Student(name={self.name}, age={self.age}, percent={self.percent})"  
    def __eq__(self, other):  
        if not isinstance(other, Student):  
            return NotImplemented  
        return (self.name == other.name and self.age == other.age and self.percent == other.percent)
s1 = Student("Alice", 20, 90.0)
s2 = Student("Bob", 22, 85.5)
print(s1)
print(s1 == s2)

خروجی این کد مشابه کد بالا خواهد بود −

Student(name='Alice', age=20, percent=90.0)
False

مقادیر پیش‌فرض در Dataclass

شما همچنین می‌توانید مقادیر پیش‌فرض برای ویژگی‌ها در یک dataclass ارائه دهید. اگر در هنگام ایجاد یک نمونه مقداری ارائه نشود، از مقدار پیش‌فرض استفاده خواهد شد. در کد زیر، ما مقدار پیش‌فرض 0.0 را برای ویژگی percent قرار داده‌ایم.

from dataclasses import dataclass

@dataclass
class Student:
    name: str
    age: int
    percent: float = 0.0  # Default value for percent

s1 = Student("Alice", 20)
s2 = Student("Bob", 22, 85.5)
print(s1)
print(s2)

خروجی کد بالا به صورت زیر خواهد بود −

Student(name='Alice', age=20, percent=0.0)
Student(name='Bob', age=22, percent=85.5)

Dataclass با مقادیر پیش‌فرض تغییرپذیر (Mutable)

مقادیر پیش‌فرض تغییرپذیر به مقادیر پیش‌فرضی اشاره دارند که می‌توانند پس از ایجاد نمونه تغییر کنند، مانند لیست‌ها یا دیکشنری‌ها. هنگام استفاده از مقادیر پیش‌فرض تغییرپذیر در یک dataclass، توصیه می‌شود از تابع ()field از ماژول dataclasses با پارامتر default_factory استفاده کنید. زیرا اگر مستقیماً از یک شئ تغییرپذیر به عنوان مقدار پیش‌فرض استفاده کنید، بین تمام نمونه‌های dataclass به اشتراک گذاشته خواهد شد. این امر می‌تواند منجر به مشکلات امنیتی و رفتارهای غیرمنتظره شود.

در کد زیر، ما یک dataclass به نام Course با یک مقدار پیش‌فرض تغییرپذیر برای ویژگی students تعریف کرده‌ایم.

from dataclasses import dataclass, field
from typing import List
@dataclass
class Course:
    name: str
    students: List[str] = field(default_factory=list)  # Mutable default value

course1 = Course("Math")
course2 = Course("Science", ["Alice", "Bob"])
course1.students.append("Charlie")
print(course1)
print(course2)

خروجی کد بالا به صورت زیر خواهد بود −

Course(name='Math', students=['Charlie'])
Course(name='Science', students=['Alice', 'Bob'])

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.