سطح مقدماتی (Beginner Level)
دسکریپتورها (Descriptors) یکی از قدرتمندترین ویژگیهای پایتون هستند که اغلب در پسزمینه کار میکنند، اما درک آنها دید شما را نسبت به نحوه کارکرد کلاسها تغییر میدهد.
به زبان ساده، دسکریپتور شیئی است که رفتار دسترسی به ویژگیها (Attributes) را تغییر میدهد. یعنی وقتی شما مینویسید obj.x، obj.x = 10 یا del obj.x، دسکریپتور تصمیم میگیرد چه اتفاقی بیفتد.
این دقیقاً همان مکانیزمی است که @property از آن استفاده میکند تا متدها را مانند متغیرها صدا بزنید.
مفهوم اول: چرا به دسکریپتور نیاز داریم؟
فرض کنید یک کلاس برای موجودی حساب بانکی دارید و میخواهید مطمئن شوید موجودی هرگز منفی نمیشود. در حالت عادی شاید از getter و setter استفاده کنید، اما دسکریپتور راهی تمیزتر برای مدیریت این منطق است.
مفهوم دوم: استفاده از Property (سادهترین دسکریپتور)
قبل از نوشتن دسکریپتورهای سفارشی، باید بدانید که تابع داخلی property() خودش یک دسکریپتور است.
سطح پیشرفته (Professional Level)
در سطح حرفهای، دسکریپتورها کلاسهایی هستند که پروتکل دسکریپتور (Descriptor Protocol) را پیادهسازی میکنند. این پروتکل شامل سه متد جادویی است:
__get__(self, obj, objtype)__set__(self, obj, value)__delete__(self, obj)
اگر کلاسی حتی یکی از اینها را داشته باشد، یک دسکریپتور است.
انواع دسکریپتورها
- Data Descriptor: متدهای
__set__یا__delete__را دارد. - Non-Data Descriptor: فقط متد
__get__را دارد (مثل متدها یاfunctools.cached_property).
ساخت یک دسکریپتور اعتبارسنجی (Validator)
فرض کنید میخواهید در چندین کلاس مختلف، چک کنید که یک عدد همیشه مثبت باشد. به جای تکرار @property در هر کلاس، یک کلاس دسکریپتور میسازیم.
متد __set_name__ (جدید در Python 3.6+)
در مثال بالا مجبور بودیم نام متغیر ("price") را دستی به دسکریپتور بدهیم. متد __set_name__ این کار را خودکار میکند. این متد زمانی صدا زده میشود که دسکریپتور در یک کلاس تعریف میشود.
نکات فنی و Performance
- اولویت (Precedence): یک Data Descriptor همیشه بر محتویات
__dict__نمونه (Instance) اولویت دارد. اما یک Non-Data Descriptor (مثل متدها) میتواند توسط__dict__سایه (Shadow) شود. - حافظه: استفاده از
__slots__همراه با دسکریپتورها میتواند مصرف حافظه را به شدت کاهش دهد. - کاربرد: ORMها (مثل Django و SQLAlchemy) به شدت از دسکریپتورها برای تبدیل دادههای دیتابیس به اشیاء پایتون استفاده میکنند.
# Static Snippet: How methods are actually descriptors
class MyClass:
def method(self):
pass
# When you access MyClass.method, it returns the function itself.
# When you access instance.method, the function's __get__ binds it to the instance.