سلام به همه دوستداران پایتون!
امروز هدفمون این هست که یک موضوع خیلی ساده اما کاربردی رو با هم بررسی کنیم. یک مفهومی توی پایتون وجود داره که خیلی مشابه با زبونهای برنامه نویسی دیگه هست. اما خب مثل همیشه انتظار داریم یکم باحالتر هم باشه.
اول از همه، باید یادآوری کنیم که پایتون برخلاف زبانهای برنامهنویسی دیگه به ما اجازه دسترسی مستقیم به attribute ها رو میده.
خب، بنظر میرسه که پایتون با این ترفند، کار ما رو بسیار راحت کرده. اما!
برای ساختن setter/getter توی پایتون از property کمک میگیریم.
نحوهی تعریف setter هم به صورت پایین هست:
تا اینجای کار، میشه گفت property رفتار یک متد رو به نحوی تغییر میده که کاربر فکر میکنه داره با یک ویژگی/attribute کار میکنه. به عبارت خیلی سادهتر موقع اجرای متدمون نیازی به گذاشتن () نیست.
از مهمترین مزیت این کار هم میشه به ملموس شدن یا منطقی شدن کد برای استفاده کنندهها اشاره کرد.
دقت کنید، قرار نیست ما کاری بکنیم که متدها به صورت attribute قابل دسترسی باشند! بلکه هدف اینه که کارهای محاسباتی و validation که مخصوص یک attribute هستند رو با خود attribute یکی کنیم. از دید کاربر پنهانشون میکنیم. به عبارت دیگه داریم دسترسی مستقیم رو از کاربر میگیریم.
همهی ما ممکنه که به کدهای قدیمی بر بخوریم و شاید مهمترین نکتهی که باید بهش توجه کنیم این باشه که تغییرات ما باعث شکنندگی کد نشه (Backward compatibility رو حفظ کنیم). حالا فرض کنید قطعه کدی داریم که توسعهدهنده setter/getterها به صورت پایتونیک ننوشته و از طرفی ما نمیخوایم اینقدر کد تغییر پیدا کنه که برنامههای وابسته به اون از کار بیفتند. راه حل چیه؟
راه حل دوباره property هست. property رو به دو حالت میشه استفاده کرد: حالت اول که حالت خیلی خوبش بود (چیزی که شما همیشه باید از اون استفاده کنید) استفاده از property decorator بود. اما حالت دومی هم وجود داره که به صورت زیر هست:
مثل همهی چیزهای کرهزمین property هم اونقدر کامل نیست و بعضی اوقات خیلی کسلکننده میشه. فرض کنید هدفمون این هست که یک کلاس برای ذخیره کردن اطلاعات مربوط به فیلم داشته باشیم، چیزی شبیه پایین:
اگر به کد دقت کنید، میبینید که چهار از attributeهای ما قرار هست که مقدار int بگیرند. از قضا، هیچکدوم از اینا نمیتونن مقدار کمتر از صفر (منفی) بگیرند. خوشبختانه ما روش حل این مساله رو بلدیم. کلید حل مساله استفاده از property هست، کافیه هر کجا مقدار منفی خواست وارد بشه ، سریع خطا بدیم:
همهچی ممکن است در نگاه اول خوب بنظر برسه، اما یک مشکلی اساسی توی این کد وجود داره و اون این هست که تکرار کد بشدت بالاست (Repetition). درسته که ما کارمون رو به درستی انجام دادیم و جلوی مقدار منفی رو گرفتیم؛ اما عملاً یک کار رو چهار بار تکرار کردیم.
و خب طبق معمول، حتما باید راه بهتری برای انجام این کار باشه ?.
مثلا، اگر به شکل زیر پیادهسازی می شد، چی:
توی قطعه کد بالا ما با استفاده از یک مکانیسم داریم رفتار attributeها رو مدیریت میکنیم. به این ساز و کار descriptor گفته میشه.
تا اینجای کار به هیچ عنوان property رو تعریف نکردیم؛ بلکه کارکردش رو مرور میکردیم، اما واقعیت این هست که property یک نوع descriptor محسوب میشه. تو مواردی مشابه مثال بالا، ما نیاز داریم بریم ساز و کار خاصِ خودمون رو پیادهسازی کنیم تا به اون چیزی که میخوایم برسیم (NonNegative).
پس تا الان متوجه شدیم که property ها functionality خیلی عجیبی به برنامهی ما اضافه نمیکنند فقط به ما امکان مدیریت بیشتر روی attributeها رو برای ما فراهم میکنند.
یک امکان دیگهی که propertyها به ما میدن و اینجا خیلی راجعاش صحبت نشد، lazy loading هست. یعنی محاسبات انجام نمیشن تا وقتی که نیاز بشن. دلیل اینکار هم بنظرم دیگه الان برای شما واضح هست، چون property در حقیقت دارن یک متد رو اجرا میکنند و درنتیجه تا اجرا نشن، محاسباتی هم نیز صورت نمیگیره.
توی قسمت بعدی هدفمون بررسی و ساخت descriptor هست.