دکوراتور property در برنامه نویسی پایتون

4 سال پیش

دکوراتور property در برنامه نویسی پایتون

در این درس از مجموعه آموزش برنامه نویسی سایت سورس باران، شما با دکوراتور property در برنامه نویسی پایتون آشنا خواهید شد.

برنامه نویسی پایتون یک دکوراتور توکار property  را فراهم می کند که استفاده از getter و setter ها را در برنامه نویسی شی گرا بسیار راحت تر می کند.

پیشنهاد ویژه : پکیج آموزش پروژه محور پایتون

قبل از پرداختن به جزئیات دکوراتورproperty، اجازه دهید ابتدا بفهمیم که چرا از آن ها باید استفاده کنیم.

کلاس بدون getter و setter ها

بگذارید فرض کنیم که تصمیم داریم کلاسی را بسازیم که دما را بر حسب درجه سانتیگراد ذخیره کند. همچنین می تواند روشی را برای تبدیل دما به درجه فارنهایت پیاده سازی کند. یکی از راه های انجام این کار به شرح زیر است:

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

ما می توانیم  شیئی از این کلاس را ساخت و ویژگی temperature را به دلخواه خود دستکاری کنیم:

# Basic method of setting and getting attributes in Python
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32


# Create a new object
human = Celsius()

# Set the temperature
human.temperature = 37

# Get the temperature attribute
print(human.temperature)

# Get the to_fahrenheit method
print(human.to_fahrenheit())

خروجی

۳۷
۹۸٫۶۰۰۰۰۰۰۰۰۰۰۰۰۱

رقم اعشار اضافی هنگام تبدیل به فارنهایت به دلیل نقطه ممیز شناور خطای حساب است.

هر زمان که مشخصه شی مانند temperature را مطابق شکل بالا اختصاص دادیم یا بازیابی کردیم ، پایتون آن را در ویژگی __dict__دیکشنری شی توکار جستجو می کند.

>>> human.__dict__
{'temperature': 37}

بنابراین، man.temperature به طور داخلی، [‘man.__dict__[‘temperature می ‌شود.

 

استفاده از Getters و Setters

فرض کنید می خواهیم قابلیت استفاده از کلاس سانتیگراد که در بالا تعریف شد را گسترش دهیم. ما می دانیم که دمای هر جسم نمی تواند به زیر ۲۷۳٫۱۵- درجه سانتیگراد برسد (صفر مطلق در ترمودینامیک) برای اجرای این محدودیت مقدار، کد خود را به روز کنیم.

یک راه حل واضح مخفی سازی خصیصه temperature (خصوصی کردن آن) و تعریف روشهای جدید getter و setter برای دستکاری آن خواهد بود. این میتواند بصورت زیر انجام شود:

 

# Making Getters and Setter methods
class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter method
    def get_temperature(self):
        return self._temperature

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value

همانطور که می بینیم، روش فوق دو روش جدید () get_temperature و ()set_temperature  را معرفی می کند.

بعلاوه، temperature با _temperature جایگزین می شود. از زیرخط _ برای نشان دادن متغیرهای خصوصی در پایتون استفاده می شود.

حال، اجازه دهید از این پیاده سازی استفاده کنیم:

# Making Getters and Setter methods
class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter method
    def get_temperature(self):
        return self._temperature

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value


# Create a new object, set_temperature() internally called by __init__
human = Celsius(37)

# Get the temperature attribute via a getter
print(human.get_temperature())

# Get the to_fahrenheit method, get_temperature() called by the method itself
print(human.to_fahrenheit())

# new constraint implementation
human.set_temperature(-300)

# Get the to_fahreheit method
print(human.to_fahrenheit())

خروجی

۳۷
۹۸٫۶۰۰۰۰۰۰۰۰۰۰۰۰۱
Traceback (most recent call last):
  File "<string>", line 30, in <module>
  File "<string>", line 16, in set_temperature
ValueError: Temperature below -273.15 is not possible.

این به روزرسانی محدودیت جدید را با موفقیت اجرا کرد. ما دیگر مجاز به تنظیم دمای زیر ۲۷۳٫۱۵- درجه سانتیگراد نیستیم.

توجه: متغیرهای خصوصی در واقع در پایتون وجود ندارند. برای پیاده ‌سازی آن ‌ها قواعد ساده‌ ای وجود دارد که باید از آن ‌ها پیروی کرد. خود زبان هیچ محدودیتی اعمال نمی کند.

>>> human._temperature = -300
>>> human.get_temperature()
-۳۰۰

با این حال، مشکل بزرگتر به روزرسانی فوق این است که همه برنامه هایی که کلاس قبلی ما را پیاده سازی کرده اند، باید کد خود را از obj.temperature به () obj.get_temperature و تمام عباراتی مانند obj.temperature = val به (obj.set_temperature (val تغییر دهند .

این بارساری های کد می تواند در هنگام برخورد با صدها هزار خط کد، مشکلاتی ایجاد کند.

در مجموع، به روزرسانی جدید ما با backward سازگار نبود. این جایی است که دکوراتور property برای نجات ما می آید.

کلاس property در برنامه نویسی پایتون

یک روش پایتونی برای مقابله با مشکل فوق استفاده از کلاس property است. در اینجا نحوه به روزرسانی کد ما وجود دارد:

# using property class
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature

    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value

    # creating a property object
    temperature = property(get_temperature, set_temperature)

ما یک تابع ()print  درون ()get_temperature  و ()set_temperature  اضافه کردیم تا به وضوح مشاهده کنیم که در حال اجرا هستند.

آخرین خط کد باعث ایجاد شیئ property یعنی temperature می شود. به زبان ساده، قابلیت property برخی از کدها (get_temperature و set_temperature) را به ویژگی های عضو (temperature) متصل می کند.

بیایید از این کد به روز رسانی استفاده کنیم:

# using property class
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature

    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value

    # creating a property object
    temperature = property(get_temperature, set_temperature)


human = Celsius(37)

print(human.temperature)

print(human.to_fahrenheit())

human.temperature = -300
Setting value...
Getting value...
۳۷
Getting value...
۹۸٫۶۰۰۰۰۰۰۰۰۰۰۰۰۱
Setting value...
Traceback (most recent call last):
  File "<string>", line 31, in <module>
  File "<string>", line 18, in set_temperature
ValueError: Temperature below -273 is not possible

همانطور که می بینیم، هر کدی که مقدار temperature را بازیابی کند، به طور خودکار به جای جستجوی دیکشنری (__dict__) ، اقدام به فراخوانی () get_temperature  می کند. به همین ترتیب، هر کدی که مقداری را به دما اختصاص دهد ، به طور خودکار ()set_temperature  را فراخوانی می کند.

حتی در بالا می توانیم ببینیم که ()set_temperature حتی هنگام ایجاد یک شی فراخوانی شده است.

>>> human = Celsius(37)
Setting value...

می توانید حدس بزنید چرا؟

دلیل آن این است که وقتی یک شی ایجاد می شود ، روش ()__init __  فراخوانی می شود. این روش دارای خط self.temperature = temperature است. این عبارت به طور خودکار () set_temperature را فراخوانی می کند.

به همین ترتیب ، هر دسترسی مانند c.temperature به طور خودکار ()get_temperature  را فراخوانی می کند. این همان کاری است که قابلیت property انجام می دهد. در اینجا چند مثال دیگر آورده شده است.

>>> human.temperature
Getting value
۳۷
>>> human.temperature = 37
Setting value

>>> c.to_fahrenheit()
Getting value
۹۸٫۶۰۰۰۰۰۰۰۰۰۰۰۰۱

با استفاده از property می توان دریافت که در اجرای محدودیت مقدار هیچ تغییری لازم نیست. بنابراین ، اجرای ما سازگاری Backward را دارد.

 

دکوراتور property در برنامه نویسی پایتون

در پایتون، ()property یک تابع توکار است که  شی property را می‌سازد و باز می‌گرداند. نحو این تابع عبارت است از:

property(fget=None, fset=None, fdel=None, doc=None)

 

  • fget تابعی برای بدست آوردن مقدار خصیصه‌ ها است
  • fset تابعی برای تنظیم مقدار خصیصه ‌ها است
  • fdel تابعی برای حذف خصیصه‌ ها است
  • doc یک رشته است (مانند کامنت)

همانطور که از پیاده ‌سازی مشخص شد،  آرگومان های این تابع اختیاری هستند. بنابراین ، یک شی property به سادگی می تواند به صورت زیر ایجاد شود.

>>> property()
<property object at 0x0000000003239B38>

یک شی property دارای سه روش ()getter () ، setter  و ()deleter  است تا در مرحله بعد fget ، fset و fdel مشخص شود.

temperature = property(get_temperature,set_temperature)

می تواند به صورت زیر تجزیه شود:

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

این دو قطعه کد معادل یکدیگر هستند.

برنامه نویسان آشنا با دکوراتور property می توانند تشخیص دهند که ساختار فوق می تواند به عنوان دکوریت اجرا شود.

حتی نمی توانیم نام های get_temperature و set_temperature را تعریف کنیم زیرا غیرضروری هستند و فضای نام کلاس را خراب می کنند.

برای این منظور، در حالی که توابع getter و setter را تعریف می کنیم، از نام temperature مجدداً استفاده می کنیم. بیایید ببینیم که چگونه می توان این را به عنوان یک دکوراتور پیاده سازی کرد:

# Using @property decorator
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value...")
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273 is not possible")
        self._temperature = value


# create an object
human = Celsius(37)

print(human.temperature)

print(human.to_fahrenheit())

coldest_thing = Celsius(-300)

خروجی

Setting value...
Getting value...
۳۷
Getting value...
۹۸٫۶۰۰۰۰۰۰۰۰۰۰۰۰۱
Setting value...
Traceback (most recent call last):
  File "<string>", line 29, in <module>
  File "<string>", line 4, in __init__
  File "<string>", line 18, in temperature
ValueError: Temperature below -273 is not possible

پیاده سازی فوق ساده و کارآمد است. این روش توصیه شده برای استفاده از property است.

منبع.

لیست جلسات قبل آموزش برنامه نویسی پایتون

  1. آموزش نصب و اجرای برنامه نویسی پایتون
  2. کلیدواژه ها و شناسه های برنامه نویسی پایتون
  3. دستورات، تورفتگی ها و کامنت ها در برنامه نویسی پایتون
  4. متغیرها، ثابت ها و لیترال ها در برنامه نویسی پایتون 
  5. انواع داده ها در برنامه نویسی پایتون
  6. تبدیل نوع در برنامه نویسی پایتون
  7. ورودی، خروجی و وارد کردن در برنامه نویسی پایتون
  8. عملگرها در برنامه نویسی پایتون
  9. نام و دامنه در برنامه نویسی پایتون
  10. دستور شرطی if…else در برنامه نویسی پایتون
  11. حلقه for در برنامه نویسی پایتون
  12. حلقه while در برنامه نویسی پایتون
  13. دستورات break و continue در برنامه نویسی پایتون
  14. دستور pass در برنامه نویسی پایتون
  15. توابع در برنامه نویسی پایتون
  16. آرگومان تابع در برنامه نویسی پایتون
  17. تابع بازگشتی در برنامه نویسی پایتون
  18. تابع بی نام/ تابع لامبدا در برنامه نویسی پایتون
  19. متغیرهای سراسری، محلی و غیر محلی در برنامه نویسی پایتون
  20. کلیدواژه global در برنامه نویسی پایتون
  21. ماژول های برنامه نویسی پایتون
  22. پکیج ها در برنامه نویسی پایتون
  23. اعداد و تبدیل نوع داده در برنامه نویسی پایتون 
  24. لیست در برنامه نویسی پایتون
  25. تاپل در برنامه نویسی پایتون 
  26. رشته ها در برنامه نویسی پایتون
  27. مجموعه ها در برنامه نویسی پایتون
  28. دیکشنری در برنامه نویسی پایتون
  29. عملیات ورودی/خروجی در برنامه نویسی پایتون 
  30. دایرکتوری و مدیریت فایل ها در برنامه نویسی پایتون
  31. خطاها و استثناهای توکار در برنامه نویسی پایتون
  32. مدیریت استثناها در برنامه نویسی پایتون
  33. استثناهای تعریف شده توسط کاربر در برنامه نویسی پایتون
  34. برنامه ‌نویسی شی گرا در پایتون
  35. اشیا و کلاس ها در برنامه نویسی پایتون
  36. وراثت در برنامه نویسی پایتون
  37. وراثت چندگانه در برنامه نویسی پایتون
  38. سربارگذاری عملگرها در برنامه نویسی پایتون
  39. تکرار کننده ها در برنامه نویسی پایتون
  40. Generator در برنامه نویسی پایتون
  41. بستار در برنامه نویسی پایتون
  42. دکوراتور در برنامه نویسی پایتون
0
برچسب ها :
نویسنده مطلب erfan molaei

دیدگاه شما

بدون دیدگاه