English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
يملك بايثون فكرة عظيمة تُدعى الخاصية، وتجعل حياة مطوري البرمجة الموجهة للأحداث أسهل.
قبل أن نتعرف على تعريف وتوضيح مفهوم @property، دعونا نعرف لماذا نحتاج إلى استخدامه أولاً.
افترض أنك قررتإنشاءفئة تخزن درجة الحرارة بالدرجة المئوية. ستحقق أيضًا من تحويل درجة الحرارة إلى درجة حرارة فهرنهايت. إحدى الطرق هي:
class Celsius: def __init__(self, temperature = 0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32
يمكننا من خلال هذه الفئة إنتاج العناصر وتعديل الخاصية temperature حسب الحاجة. حاول هذه في بيئة بايثون.
>>> # إنشاء عنصر جديد >>> man = Celsius() >>> # ضبط درجة الحرارة >>> man.temperature = 37 >>> # الحصول على درجة الحرارة >>> man.temperature 37 >>> # الحصول على درجة الحرارة الفهرنية >>> man.to_fahrenheit() 98.60000000000001
تكون الأعداد الصغيرة الإضافية في التحويل إلى درجة حرارة فهرنهايت بسبب الأخطاء في العمليات العددية العشوائية (عند محاولة 1.1 + 2.2 في معالج بايثون).
كما هو موضح أعلاه، في كل مرة نقوم فيها بإعادة تخصيص أو استرجاع أي خاصية للعنصر (مثلtemperatureعندما يتم الوصول إلى )، يقوم بايثون بالبحث في قاموس __dict__ للعنصر.
>>> man.__dict__ {'temperature': 37}
لذلك، أصبح man.temperature = man.__dict__['temperature'].
الآن، لنفترض أن دوراتنا شائعة بين العملاء وأنهم بدأوا في استخدامها في برامجهم. لقد قاموا بإعادة تخصيص الأشياء المختلفة.
في يوم من الأيام، جاء لنا عميل موثوق، وأوصى بأن لا يمكن أن تكون درجة الحرارة أقل من -273 درجة مئوية (يمكن أن يقول طالبون في التخصص الحراري إنها في الواقع -273.15 درجة مئوية)، وتُعرف أيضًا بدرجة الحرارة الصفرية المطلقة. لقد طلب منا أيضًا تنفيذ هذه القيود. كشركة نبحث عن رضا العملاء، نحن سعداء بالاستماع إلى هذه المقترحات وطرح إصدار 1.01 (تحديث للفئة الحالية).
من الممكن حل القيود المذكورة أعلاه بطريقة واضحة عبر إخفاء الخاصية temperature (تقديمها كخاصة) و تعريف واجهات getter و setter جديدة للتعامل معها. يمكن القيام بذلك كما يلي.
class Celsius: def __init__(self, temperature = 0): self.set_temperature(temperature) def to_fahrenheit(self): return (self.get_temperature() * 1.8) + 32 # new update def get_temperature(self): return self._temperature def set_temperature(self, value): if value < -273: raise ValueError("-273 درجة مئوية غير ممكنة") self._temperature = value
نحن نستطيع رؤية get_temperature()،set_temperature() تم تعريفها بالفعل كوظائف جديدة، بالإضافة إلى ذلك، تم استبدال temperature باستخدام _temperature. يُعتبر الحرف _ الموجود في البداية دليلاً على المتغيرات الخاصة في بايثون.
>>> c = Celsius(-277) Traceback (أحدث استدعاء): ... ValueError: لا يمكن لدرجة الحرارة أن تكون أقل من -273 >>> c = Celsius(37) >>> c.get_temperature() 37 >>> c.set_temperature(10) >>> c.set_temperature(-300) Traceback (أحدث استدعاء): ... ValueError: لا يمكن لدرجة الحرارة أن تكون أقل من -273
تم تنفيذ هذا التحديث بنجاح وتم تطبيق الحد الجديد. لم يعد مسموحًا لنا بتعيين درجة الحرارة أقل من -273.
يرجى ملاحظة أن المتغيرات الخاصة غير موجودة في بايثون. يجب فقط اتباع بعض المعايير. لا يوجد أي تحديد في اللغة نفسها.
>>> c._temperature = -300 >>> c.get_temperature() -300
لكن هذا ليس مشكلة كبيرة. أكبر مشكلة في هذا التحديث هي أن جميع العملاء الذين قاموا بتطبيق هذا الفئة السابقة يجب عليهم تعديل كود obj.temperature إلى obj.get_temperature()، وكذلك جميع التخصيصات (مثل obj.temperature من = val إلى obj.set_temperature(val).
سيكون هذا التعديل مصدر إزعاج للعملاء بسبب عشرات الآلاف من الأسطر من الكود.
بشكل عام، تحديثنا الجديد ليس متوافقًا مع الإصدارات السابقة. هنا يأتي دور @property.
يستخدم بايثون خاصية property للتعامل مع هذه المشكلة. يمكننا تنفيذ ذلك بهذه الطريقة.
class Celsius: def __init__(self, temperature = 0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 def get_temperature(self): print("القيمة التي تم الحصول عليها") return self._temperature def set_temperature(self, value): if value < -273: raise ValueError("درجة تحت الصفر 273 غير ممكنة") print("قيمة معينة") self._temperature = value temperature = property(get_temperature, set_temperature)
وعندما يتم تشغيله، يتم إصدار التالي في بيئة الشل.
>>> c = Celsius()
لقد أضفنا دالة print() في get temperature() وset temperature() لرؤية تنفيذها بشكل واضح.
آخر سطر الكود يخلق جسم الـproperty temperature. على اختصار، الخاصية تضيف بعض الكود (get_temperature وset_temperature) إلى الوصول إلى الخاصية (temperature).
任何检索温度值的代码都将自动调用get_temperature()而不是字典(__dict__)查找。 同样,任何为温度分配值的代码都会自动调用set_temperature()。 这是Python中的一项很酷的功能。
我们可以在上面看到即使创建对象时也会调用set_temperature()。
你能猜出为什么吗?
原因是创建对象时,将调用__init__()方法。 此方法的行是self.temperature = temperature。 此分配自动称为set_temperature()。
>>> c.temperature Getting value 0
同样,任何访问如c.temperature都会自动调用get_temperature()。 这就是属性的作用。 这里还有一些实例。
>>> c.temperature = 37 Setting value >>> c.to_fahrenheit() Getting value 98.60000000000001
通过使用属性,我们可以看到,我们修改了类并实现了值约束,而无需更改客户端代码。因此,我们的实现是向后兼容的。
最后请注意,实际温度值存储在私有变量_temperature中。 temperature属性是一个属性对象,它提供了与此私有变量的接口。
在Python中,property()是一个内置函数,用于创建并返回属性对象。该函数的签名是
property(fget=None, fset=None, fdel=None, doc=None)
其中,fget为获取属性值的函数,fset为设置属性值的函数,fdel为删除属性的函数,doc为字符串(如注释)。从实现中可以看出,这些函数参数是可选的。因此,可以简单地按照以下方式创建属性对象。
>>> property() <property object at 0x0000000003239B38>
属性对象有三个方法,getter()、setter()和deleter(),用于稍后指定fget、fset和fdel。这意味着
temperature = property(get_temperature, set_temperature)
يمكن أيضًا تحليلها
# إنشاء خاصية فارغة temperature = property() # تعيين fget temperature = temperature.getter(get_temperature) # تعيين fset temperature = temperature.setter(set_temperature)
هذه السطور البرمجية متساوية.
معرفةزخارف بيانثونيمكن للبرمجيين التعرف على أن هذه التركيبات يمكن تحقيقها كزخارف.
يمكننا الذهاب إلى أبعد من ذلك، دون تعريف الأسماءget_temperature،set_temperature، لأنها غير ضرورية وقد تؤثر على مجال التسمية للفئة. لذلك، نعيد استخدام الاسمtemperature عند تعريف وظائف الحصول والتعيين. هذا يمكن القيام به.
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("الحصول على القيمة") return self._temperature @temperature.setter def temperature(self, value): if value < -273: raise ValueError("درجة تحت الصفر 273 غير ممكنة") print("قيمة معينة") self._temperature = value
التحقيق أعلاه هو طريقة بسيطة وموصى بها لإنشاء الخصائص. عند البحث عن الخصائص في بيانثون، من المحتمل أن تجد هذه الأنواع من التركيبات.
حسنًا، اليوم على هذا النحو.