Property Decorators متقدمة
جزء من قسم البرمجة كائنية التوجه في رحلة Python على Coddy. الدرس 31 من 64.
توفر مزخرفات الخصائص المتقدمة تحكمًا أكثر تطورًا في الوصول إلى السمات، بما في ذلك الخصائص المحسوبة وعمليات الحذف والإدارة الكاملة للخصائص.
إليك مثالًا على الخصائص المحسوبة التي تستمد قيمها من سمات أخرى:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)استخدم الخصائص المحسوبة مثل السمات العادية:
rect = Rectangle(5, 3)
print(rect.area) # 15 - محسوبة تلقائيًا
print(rect.perimeter) # 16 - محسوبة تلقائيًاأنشئ خاصية باستخدام دوال getter وsetter وdeleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0استخدم الوظائف الكاملة للخاصية:
temp = Temperature()استخدم أداة الضبط مع التحقق:
temp.temperature = 25
print(temp.temperature) # 25
# temp.temperature = -300 # سيؤدي إلى إثارة ValueErrorاستخدم الحاذف:
del temp.temperature
print(temp.temperature) # 0أنشئ مثالًا أكثر تعقيدًا باستخدام نتيجة لعبة:
class Player:
def __init__(self, name):
self.name = name
self._score = 0
self._level = 1
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if value >= 0:
self._score = value
self._level = (value // 1000) + 1
else:
raise ValueError("Score cannot be negative")
@score.deleter
def score(self):
print(f"Resetting {self.name}'s progress")
self._score = 0
self._level = 1
@property
def level(self):
return self._level
player = Player("Alice")
player.score = 2500
print(f"Score: {player.score}, Level: {player.level}") # النقاط: 2500، المستوى: 3
del player.score
print(f"Score: {player.score}, Level: {player.level}") # النقاط: 0، المستوى: 1المخرجات:
15
16
25
Resetting temperature to 0
0
Score: 2500, Level: 3
Resetting Alice's progress
Score: 0, Level: 1النقطة الأساسية: تتيح مزخرفات الخصائص المتقدمة إنشاء خصائص محسوبة (تُحسب انطلاقًا من بيانات أخرى)، وحذف الخصائص باستخدام @property.deleter، والتحكم الكامل في الحصول على السمات وتعيينها وحذفها. وهذا ينشئ واجهات بديهية مع الحفاظ على التحقق القوي من صحة البيانات والتغليف.
التحدي
متوسطفي هذا التحدي، ستنفّذ فئة Rectangle مع تغليف مناسب والتحقق من صحة الخصائص.
rectangle.py- هذا هو الملف الذي تحتاج إلى تعديله، ويحتوي على تعليقات TODO لإرشادك في تنفيذ الحلdriver.py- يحتوي على سيناريوهات اختبار موسّعة (لا تعدّله)
- خزّن القيم في السمات المحمية (الداخلية)
_widthو_height - أنشئ خصائص لـ
widthوheightمع التحقق من الصحة (يجب أن تكون القيم موجبة)- ارفع رسائل ValueError المناسبة كما هو محدد في تعليقات TODO
- مهم: تحقّق مما إذا كانت القيمة أقل من أو تساوي 0، ثم ارفع الخطأ (يضمن ذلك سلوكًا متسقًا)
- نفّذ خصائص للقراءة فقط لكل من
areaوperimeter - أنشئ خاصية
dimensionsبوظائف getter وsetter وdeleter كما هو موضح في تعليقات TODO- مهم: استخدم في setter صياغة فكّ التعبئة للصفوف:
width, height = dimensions
- مهم: استخدم في setter صياغة فكّ التعبئة للصفوف:
جرّب بنفسك
from rectangle import Rectangle
# معالج حالات الاختبار
test_case = input()
# اختبار الوظائف الأساسية
if test_case == "default_test":
rect = Rectangle(5, 3)
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
# اختبار الخاصية dimensions
print(f"Dimensions: {rect.dimensions}")
rect.dimensions = (10, 8)
print(f"New area: {rect.area}")
# اختبار التحقق من صحة القيم
try:
rect.width = -2
except ValueError as e:
print(f"Validation error: {e}")
# اختبار أداة الحذف
del rect.dimensions
print(f"After reset: {rect.dimensions}")
# اختبار باستخدام قيم صفرية
elif test_case == "zero_values":
try:
rect = Rectangle(0, 5)
except ValueError as e:
print(f"Error creating rectangle: {e}")
try:
rect = Rectangle(5, 0)
except ValueError as e:
print(f"Error creating rectangle: {e}")
# اختبار باستخدام قيم سالبة
elif test_case == "negative_values":
rect = Rectangle(5, 3)
original_dimensions = rect.dimensions
try:
rect.dimensions = (5, -3)
except ValueError as e:
print(f"Error setting dimensions: {e}")
print(f"Dimensions after failed update: {rect.dimensions}")
print(f"Original dimensions preserved: {rect.dimensions == original_dimensions}")
# اختبار باستخدام قيم كبيرة
elif test_case == "large_values":
rect = Rectangle(1000000, 2000000)
print(f"Large rectangle area: {rect.area}")
print(f"Large rectangle perimeter: {rect.perimeter}")
# اختبار باستخدام قيم ذات فاصلة عائمة
elif test_case == "float_values":
rect = Rectangle(3.5, 2.75)
print(f"Dimensions: {rect.dimensions}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
rect.dimensions = (1.1, 2.2)
print(f"New area with float dimensions: {rect.area}")
# اختبار باستخدام أخطاء الأنواع
elif test_case == "type_errors":
try:
rect = Rectangle("5", 3)
except Exception as e:
print(f"Type error during creation: {type(e).__name__}: {e}")
rect = Rectangle(5, 3)
try:
rect.dimensions = 10 # ليس صفًّا
except Exception as e:
print(f"Type error setting dimensions: {type(e).__name__}: {e}")
# اختبار عدة عمليات على الخصائص
elif test_case == "property_operations":
rect = Rectangle(5, 10)
print(f"Initial - Width: {rect.width}, Height: {rect.height}, Area: {rect.area}")
rect.width = 8
print(f"After width change - Width: {rect.width}, Area: {rect.area}")
rect.height = 6
print(f"After height change - Height: {rect.height}, Area: {rect.area}")
rect.dimensions = (12, 9)
print(f"After dimensions change - Dimensions: {rect.dimensions}, Area: {rect.area}")
del rect.dimensions
print(f"After reset - Dimensions: {rect.dimensions}, Area: {rect.area}")
# اختبار الحالات الحدية للتحقق من صحة الخصائص
elif test_case == "validation_edge_cases":
rect = Rectangle(5, 3)
try:
rect.width = 0
except ValueError as e:
print(f"Zero width error: {e}")
# يجب قبول قيمة موجبة صغيرة جدًا
rect.height = 0.0001
print(f"Small height accepted: {rect.height}")
print(f"Area with small height: {rect.area}")
# اختبار عدة مستطيلات
elif test_case == "multiple_rectangles":
rect1 = Rectangle(5, 3)
rect2 = Rectangle(10, 2)
rect3 = Rectangle(4, 4)
print(f"Rectangle 1 - Area: {rect1.area}, Perimeter: {rect1.perimeter}")
print(f"Rectangle 2 - Area: {rect2.area}, Perimeter: {rect2.perimeter}")
print(f"Rectangle 3 - Area: {rect3.area}, Perimeter: {rect3.perimeter}")
# تعديل كل مستطيل
rect1.width = 7
rect2.height = 5
rect3.dimensions = (6, 6)
print(f"After modifications:")
print(f"Rectangle 1 - Dimensions: {rect1.dimensions}")
print(f"Rectangle 2 - Dimensions: {rect2.dimensions}")
print(f"Rectangle 3 - Dimensions: {rect3.dimensions}")
# اختبار الأداء مع عدد كبير من العمليات
elif test_case == "performance_test":
rect = Rectangle(5, 5)
# تنفيذ عدد كبير من عمليات الخصائص
for i in range(1000):
rect.width = i % 10 + 1 # القيم 1-10
rect.height = i % 5 + 1 # القيم 1-5
area = rect.area # الوصول إلى الخاصية المحسوبة
perimeter = rect.perimeter # الوصول إلى الخاصية المحسوبة
dims = rect.dimensions # الوصول إلى دالة جلب الخاصية
print(f"Final state after 1000 operations:")
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكال3خصائص الـ Class
متغيرات الـ Instance مقابل متغيرات الـ ClassProperty Decoratorsالسمات الخاصةمراجعة - مدير الحساب البنكي6التغليف (Encapsulation)
الأعضاء العامة والمحمية والخاصةمحددات الوصولإخفاء المعلوماتProperty Decorators متقدمةمراجعة - نظام سجلات الطلابتدرّب بنفسك: مترجم Python عبر الإنترنت