کلاسهای داده پایتون میتوانند کلاسهای پایتون شما را کمتر و در عین حال قدرتمندتر کنند. در اینجا مقدمه ای برای استفاده از کلاس های داده در برنامه های پایتون شما آورده شده است.
- نمونه کلاس داده پایتون
- راهاندازی اولیه کلاس داده پیشرفته پایتون
- سفارشی کردن فیلدهای کلاس داده پایتون با تابع فیلد
- کنترل مقداردهی اولیه کلاس داده پایتون
- چه زمانی از کلاسهای داده Python استفاده کنیم—و چه زمانی از آنها استفاده نکنیم< /li>
همه چیز در پایتون یک شی است یا به قول معروف. اگر می خواهید اشیاء سفارشی خود را با ویژگی ها و روش های خاص خود ایجاد کنید، از شی class
پایتون برای تحقق آن استفاده می کنید. اما ایجاد کلاسها در پایتون گاهی اوقات به معنای نوشتن بارهای کد تکراری و boilerplate برای تنظیم نمونه کلاس از روی پارامترهای ارسال شده به آن یا ایجاد توابع مشترک مانند عملگرهای مقایسه است.
کلاسهای داده که در Python 3.7 معرفی شدهاند (و به Python 3.6 بکپورت شدهاند)، یک ابزار مفید و کمتر ارائه میکنند. روشی پرمخاطب برای ایجاد کلاس ها بسیاری از کارهای رایجی که در یک کلاس انجام میدهید، مانند نمونهسازی ویژگیها از آرگومانهای ارسال شده به کلاس، را میتوان به چند دستورالعمل اساسی تقلیل داد.
نمونه کلاس داده پایتون
در اینجا یک مثال ساده از یک کلاس معمولی در پایتون آمده است:
class Book:
'''Object for tracking physical books in a collection.'''
def __init__(self, name: str, weight: float, shelf_id:int = 0):
self.name = name
self.weight = weight # in grams, for calculating shipping
self.shelf_id = shelf_id
def __repr__(self):
return(f"Book(name={self.name!r},
weight={self.weight!r}, shelf_id={self.shelf_id!r})")
بزرگترین سردرد در اینجا روشی است که هر یک از آرگومانهای ارسال شده به __init__
باید در ویژگیهای شیء کپی شوند. اگر فقط با کتاب
سر و کار دارید، این خیلی بد نیست، اما اگر مجبور باشید با Bookshelf
، Library
، انبار
و غیره؟ به علاوه، هرچه کد بیشتری را باید با دست تایپ کنید، احتمال اشتباه شما بیشتر میشود.
در اینجا همان کلاس پایتون است که به عنوان یک کلاس داده پایتون پیاده سازی شده است:
from dataclasses import dataclass
@dataclass
class Book:
'''Object for tracking physical books in a collection.'''
name: str
weight: float
shelf_id: int = 0
وقتی ویژگیهایی را که به آنها فیلدها میگویند، در یک کلاس داده مشخص میکنید، تزئینکننده @dataclass
بهطور خودکار همه کدهای لازم برای مقداردهی اولیه آنها را تولید میکند. همچنین اطلاعات نوع را برای هر ویژگی حفظ میکند، بنابراین اگر از یک لایه کد مانند mypy
استفاده میکنید، اطمینان حاصل میکند که انواع مناسبی از متغیرها را برای سازنده کلاس ارائه میدهید.
کار دیگری که @dataclass
در پشت صحنه انجام میدهد، ایجاد خودکار کد برای تعدادی از متدهای dunder رایج در کلاس است. در کلاس معمولی بالا، ما باید __repr__
خود را ایجاد میکردیم. در کلاس داده، دکوراتور @dataclass
__repr__
را برای شما ایجاد میکند.
هنگامی که یک کلاس داده ایجاد می شود، از نظر عملکردی با یک کلاس معمولی یکسان است. هیچ جریمه عملکردی برای استفاده از کلاس داده وجود ندارد. فقط یک جریمه عملکرد کوچک برای اعلام کلاس به عنوان یک کلاس داده وجود دارد، و این یک هزینه زمانی است که شیء کلاس داده ایجاد شود.
راه اندازی اولیه کلاس داده پیشرفته پایتون
تزیینکننده کلاس داده میتواند گزینههای اولیهسازی را خودش انتخاب کند . در بیشتر مواقع نیازی به تهیه آنها نخواهید داشت، اما آنها می توانند برای موارد لبه خاصی مفید باشند. در اینجا برخی از مفیدترین آنها آمده است (همگی درست/نادرست
هستند):
frozen
: نمونه های کلاسی را تولید می کند که فقط خواندنی هستند. پس از تخصیص داده ها، نمی توان آنها را تغییر داد.slots
: به نمونههایی از کلاسهای داده اجازه میدهد تا تنها با اجازه دادن به فیلدهایی که بهصراحت در کلاس تعریف شدهاند، از حافظه کمتری استفاده کنند.kw_only
: وقتی تنظیم شود، تمام فیلدهای کلاس فقط کلیدواژه هستند.
سفارشی کردن فیلدهای کلاس داده پایتون با عملکرد field
روش پیشفرض کار کلاسهای داده باید برای اکثر موارد استفاده درست باشد. با این حال، گاهی اوقات لازم است نحوه تنظیم اولیه فیلدهای کلاس داده خود را به دقت تنظیم کنید. همانطور که در زیر نشان داده شده است، می توانید از عملکرد field
برای تنظیم دقیق استفاده کنید:
from dataclasses import dataclass, field
from typing import List
@dataclass
class Book:
'''Object for tracking physical books in a collection.'''
name: str
condition: str = field(compare=False)
weight: float = field(default=0.0, repr=False)
shelf_id: int = 0
chapters: List[str] = field(default_factory=list)
وقتی یک مقدار پیشفرض را برای نمونهای از field
تنظیم میکنید، بسته به پارامترهایی که به field
میدهید، نحوه تنظیم فیلد را تغییر میدهد. اینها رایجترین گزینههای مورد استفاده برای فیلد
هستند (گزینههای دیگری نیز وجود دارد):
default
: مقدار پیشفرض را برای فیلد تنظیم میکند. اگر الف) ازfield
برای تغییر سایر پارامترهای فیلد استفاده میکنید، و ب) میخواهید یک مقدار پیشفرض در قسمت بالای آن تنظیم کنید، باید ازdefault
استفاده کنید. . در این مورد، ازپیشفرض
برای تنظیموزن
به۰.۰
استفاده میکنیم.default_factory
: نام تابعی را ارائه میکند که هیچ پارامتری ندارد و مقداری از شی را به عنوان مقدار پیشفرض فیلد برمیگرداند. در این مورد، ما میخواهیمفصلها
یک لیست خالی باشند.repr
: بهطور پیشفرض (درست
)، کنترل میکند که آیا فیلد مورد نظر در__repr__
برای کلاس دادهای که بهطور خودکار ایجاد میشود، نشان داده شود. در این مورد، ما نمیخواهیم وزن کتاب در__repr__
نشان داده شود، بنابراین ازrepr=False
برای حذف آن استفاده میکنیم.مقایسه
: به طور پیشفرض (True
)، شامل فیلد در روشهای مقایسه است که به طور خودکار برای کلاس داده تولید میشود. در اینجا، ما نمیخواهیم ازشرط
به عنوان بخشی از مقایسه دو کتاب استفاده شود، بنابراینcompare=False
را تنظیم میکنیم.
توجه داشته باشید که باید ترتیب فیلدها را طوری تنظیم کنیم که فیلدهای غیرپیشفرض اول باشند.
کنترل مقداردهی اولیه کلاس داده پایتون
در این مرحله احتمالاً از خود میپرسید: اگر روش __init__
یک کلاس داده بهطور خودکار تولید میشود، چگونه میتوانم برای ایجاد تغییرات دقیقتر روی فرآیند init کنترل داشته باشم؟
>
__post_init__
روش __post_init__
را وارد کنید. اگر روش __post_init__
را در تعریف کلاس داده خود بگنجانید، میتوانید دستورالعملهایی برای اصلاح فیلدها یا سایر دادههای نمونه ارائه کنید:
from dataclasses import dataclass, field
from typing import List
@dataclass
class Book:
'''Object for tracking physical books in a collection.'''
name: str
weight: float = field(default=0.0, repr=False)
shelf_id: Optional[int] = field(init=False)
chapters: List[str] = field(default_factory=list)
condition: str = field(default="Good", compare=False)
def __post_init__(self):
if self.condition == "Discarded":
self.shelf_id = None
else:
self.shelf_id = 0
در این مثال، ما یک روش __post_init__
برای تنظیم shelf_id
به هیچک
ایجاد کردهایم، اگر شرط کتاب بهعنوان مقداردهی اولیه شده باشد." حذف شد"
. توجه داشته باشید که چگونه از field
برای مقداردهی اولیه shelf_id
استفاده میکنیم و init
را بهعنوان False
به فیلد
این بدان معنی است که shelf_id
در __init__
مقداردهی اولیه نمیشود.
InitVar
یک راه دیگر برای سفارشی کردن تنظیمات کلاس داده پایتون استفاده از نوع InitVar
است. این به شما امکان میدهد فیلدی را مشخص کنید که به __init__
و سپس به __post_init__
ارسال شود، اما در نمونه کلاس ذخیره نخواهد شد.
با استفاده از InitVar
، میتوانید هنگام تنظیم کلاس داده، پارامترهایی را دریافت کنید که فقط در هنگام تنظیم اولیه استفاده میشوند. این یک مثال است:
from dataclasses import dataclass, field, InitVar
from typing import List
@dataclass
class Book:
'''Object for tracking physical books in a collection.'''
name: str
condition: InitVar[str] = "Good"
weight: float = field(default=0.0, repr=False)
shelf_id: int = field(init=False)
chapters: List[str] = field(default_factory=list)
def __post_init__(self, condition):
if condition == "Unacceptable":
self.shelf_id = None
else:
self.shelf_id = 0
تنظیم نوع یک فیلد به InitVar
(که نوع فیلد فرعی آن نوع فیلد واقعی است) به @dataclass
علامت میدهد تا آن فیلد را به یک فیلد کلاس داده تبدیل نکنید، بلکه به آن منتقل شود. داده ها همراه با __post_init__
به عنوان آرگومان.
در این نسخه از کلاس Book
مان، condition
را بهعنوان یک فیلد در نمونه کلاس ذخیره نمیکنیم. ما فقط از شرط
در مرحله اولیه سازی استفاده می کنیم. اگر متوجه شدیم که شرط
روی «غیرقابل قبول»
تنظیم شده است، shelf_id
را روی هیچکدام
تنظیم میکنیم — اما این کار را نمیکنیم. خود را condition
در نمونه کلاس ذخیره کنید.
چه زمانی از کلاسهای داده پایتون استفاده کنیم—و چه زمانی از آنها استفاده نکنیم
یک سناریوی رایج برای استفاده از کلاسهای داده، جایگزینی برای namedtuple. کلاسهای داده رفتارهای مشابه و بیشتر را ارائه میدهند، و میتوان آنها را تغییرناپذیر کرد (همانطور که namedtuple
ها هستند) با استفاده از @dataclass(frozen=True) )
به عنوان دکوراتور.
یک مورد استفاده احتمالی دیگر جایگزینی دیکشنریهای تودرتو است که کار با آنها ممکن است ناشیانه باشد، با نمونههای تودرتو از کلاسهای داده. اگر یک کلاس داده کتابخانه
دارید، با ویژگی فهرستی از قفسهها
، میتوانید از یک کلاس داده ReadingRoom
برای پر کردن آن فهرست استفاده کنید، سپس روشهایی را به آن اضافه کنید. دسترسی به اقلام تو در تو (مانند کتاب روی قفسه در یک اتاق خاص) را آسان کنید.
اما لازم نیست هر کلاس پایتون یک کلاس داده باشد. اگر یک کلاس را عمدتاً بهعنوان روشی برای گروهبندی دستهای از روشهای استاتیک ایجاد میکنید، نه بهعنوان محفظهای برای دادهها، نیازی نیست آن را به یک کلاس داده تبدیل کنید. به عنوان مثال، یک الگوی رایج با تجزیه کننده ها، داشتن کلاسی است که یک درخت نحو انتزاعی را می گیرد، درخت را راه می اندازد، و بر اساس نوع گره، فراخوانی ها را به روش های مختلف در کلاس ارسال می کند. از آنجایی که کلاس تجزیه کننده داده های بسیار کمی دارد، کلاس داده در اینجا مفید نیست.
پست های مرتبط
نحوه استفاده از کلاس های داده پایتون
نحوه استفاده از کلاس های داده پایتون
نحوه استفاده از کلاس های داده پایتون