خواص (Properties)

property (خصوصیت) روشی برای دسترسی به متغیرهایی با سطح دسترسی private می‌باشد. همانطور که در درس قبلی هم توضیح داده شد، اعضای خصوصی یک کلاس در خارج از کلاس در دسترس نیستند. حال اگر بخواهیم به اعضای خصوصی کلاس در خارج از کلاس دسترسی داشته باشیم و مقدار آنها را چاپ کنیم و یا به آنها مقداری اختصاص دهیم باید چکار کنیم. چاره کار استفاده از Property ها است.

این Decorator دارای سه بخش می‌باشد، یک بخش جهت مقدار دهی (بلوک setter) و یک بخش برای دسترسی به مقدار (بلوک getter) یک داده private می‌باشد و یک بخش جهت پاک کردن مقدار (بلوک deleter). در مثال زیر نحوه تعریف و استفاده از این Decorator آمده است :

  1: class Person:
  2: 
  3:     __name   = "No Name"
  4:     __age    = 0
  5:     __height = 0.0
  6: 
  7:     def __init__(self):
  8:         self.__name  
  9:         self.__age   
 10:         self.__height
 11: 
 12:     @property                 
 13:     def Name(self):           
 14:         return self.__name;   
 15:                               
 16:     @Name.setter              
 17:     def Name(self, value):    
 18:         self.__name = value;  
 19:                               
 20:     @Name.deleter             
 21:     def Name(self):           
 22:         del self.__name       
 23:                                                       
 24:     @property                 
 25:     def Age(self):            
 26:         return self.__age     
 27:                               
 28:     @Age.setter               
 29:     def Age(self, value):     
 30:         self.__age = value;   
 31:                               
 32:     @Age.deleter              
 33:     def Age(self):            
 34:         del self.__age;       
 35: 
 36:     @property                 
 37:     def Height(self):         
 38:         return self.__height  
 39:                               
 40:     @Height.setter            
 41:     def Height(self, value):  
 42:         self.__height = value;
 43:                               
 44:     @Height.deleter           
 45:     def Height(self):         
 46:         del self.__height;    
 47: 
 48: person1 = Person();
 49: person1.Name   = "Frank"; 
 50: person1.Age    = 19;       
 51: person1.Height = 162;
 52: print("name: {0}".format(person1.Name));
 53: print("age: {0} years old".format(person1.Age));
 54: print("height: {0}cm".format(person1.Height));
 55: 
 56: print(); #Seperator 
 57: 
 58: person2 = Person();
 59: person2.Name   = "Ronald";
 60: person2.Age    = 25;       
 61: person2.Height = 174;   
 62: print("name: {0}".format(person2.Name));
 63: print("age: {0} years old".format(person2.Age));
 64: print("height: {0}cm".format(person2.Height));
Name: Jack
Name: Frank
Age: 19 years old
Height: 162cm

Name: Ronald
Age: 25 years old
Height: 174cm

در برنامه بالا نحوه استفاده از property آمده است. همانطور که مشاهده می‌کنید در این برنامه ما سه فیلد (خطوط 5-3) تعریف کرده‌ایم (سه فیلد با سطح دسترسی private).

__name
__age
__height

دسترسی به مقادیر این فیلدها فقط از طریق property های ارائه شده (خطوط 46-12) امکان پذیر است. همانطور که احتمالا متوجه شده اید، به ازای هر فیلد یک Property تعریف شده است. هر Property از سه متد تشکیل شده است :

@property
def propertyName(self):         
    #Some Code   
                            
@propertyName.setter          
def propertyName(self, value):  
    #Some Code

@propertyName.deleter
del propertyName(self):         
    #Some Code  

همانطور که در کد بالا مشاهده می کنید، قبل از تعریف متد اول propery@، قبل از تعریف متد دوم، عبارت propertyName.setter@ و قبل از متد سوم عبارت propertyName.deleter@ نوشته می شود. propertyName همان نام متد می باشد. نام متدها طبق قرارداد باید همانند نام فیلدها است با این تفاوت که با حرف بزرگ شروع می شود. مثلا در مثال نام فیلد name و نام سه متد مربوطه Name می باشد. و اما کار این سه متد چیست؟

به کلمه کلیدی value در داخل متدهای setter، توجه کنید. Value همان مقداری است که از طریق property به فیلد اختصاص می‌دهیم. برای اختصاص یک مقدار به یک فیلد از طریق property کافیست که به صورت زیر عمل کنید :

Object.Property = Value;

این کار (قرار دادن یک مقدار بعد از علامت مساوی) به منزله فراخوانی متدهای setter است. و ما به برنامه می‌فهمانیم که می‌خواهیم از طریق این متدها یک فیلد را مقداردهی کنیم. Object شیء ایجاد شده از کلاس، Property نام پراپرتی و Value مقداری است که می‌خواهیم به فیلد اختصاص دهیم. برای دسترسی به یک خاصیت می‌توانید از علامت دات (.) استفاده کنید. مثلاً برای اختصاص مقدار به سه فیلد age ،__name__ و height__ از طریق property باید به صورت زیر عمل کنید :

person1.Name = "Frank";
person1.Age = 19;
person1.Height = 162;

دستورات بالا متدهای setter مربوط به هر property را فراخوانی کرده و مقادیری به هر یک از فیلدها اختصاص می‌دهد. برای فراخوانی متدهای getter کافیست که نام شیء و سپس علامت نقطه و در آخر نام property را بنویسیم. با این کار به برنامه می‌فهمانیم که ما نیاز به مقدار فیلد داریم.

print("Name: {0}".format(person1.Name));
print("Age: {0} years old".format(person1.Age));
print("Height: {0}cm".format(person1.Height));

به این نکته توجه کنید که در متدهای getter می‌توان تغییراتی بر روی فیلدها اعمال کرد. مثلاً فرض کنید که یک فیلد دارید که مقادیر پولی را در خود ذخیره می‌کند. شما می‌توانید در متد getter نحوه نمایش مقدار موجود در این فیلد را مشخص کنید. مثلاً خروجی به صورت سه رقم سه رقم نمایش داده شود. استفاده از property ها کد نویسی را انعطاف پذیر می‌کند مخصوصاً اگر بخواهید یک اعتبارسنجی برای اختصاص یک مقدار به فیلدها یا استخراج یک مقدار از آنها ایجاد کنید. پس می‌توان گفت که :

مثلاً شما می‌توانید یک محدودیت ایجاد کنید که فقط اعداد مثبت بین 0 تا 100 به فیلد age (سن) اختصاص داده شود. همانطور که در کد ابتدای درس مشاهده می‌کنید ما نوع فیلد age را برای سن شخص در نظر گرفته ایم. ولی کاربر می‌تواند هر رقمی به این فیلد اختصاص دهد ولی چون غیر معقولانه است و سن (age) باید یک عدد مثبت و از لحاظ عقلی عددی از 1 تا 100 باشد می‌توانیم کاربر را با استفاده از متد setter مربوط به این فیلد مجبور کنیم که رقمی بین این دو عدد را به age اختصاص دهد. خطوط 30-28 کد ابتدای درس را با کدهای زیر جایگزین کرده و مقادیر منفی و یا بالاتر از 100 را به فیلد age اختصاص داده و نتیجه را مشاهده کنید :

@Age.setter
def Age(self, value):
    if(value > 0 and value <= 100):
        self.__age = value;        
    else:                          
        age = 0;                   

مشاهده می کنید اگر کاربر بخواهد یک مقدار منفی و یا بزرگتر از صفر به فیلد age اختصاص دهد مقدار age صفر خواهد شد. اما از متد deleter اگر بخواهید که مقدار اختصاص داده شده به یک فیلد را پاک کنید استفاده می شود. بعد از خط 51 دکمه Enter را زده و کد زیر را بنویسید:

del(person1.Name)

این کد مقداری را که در خط 49 به فیلد name اختصاص داده ایم را پاک می کند و اگر برنامه را اجرا کنید مقدار پیشفرض این فیلد یعنی No Name نمایش داده می شود نه Frank.