דקורטורים מתקדמים של Property
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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}") # Score: 2500, Level: 3
del player.score
print(f"Score: {player.score}, Level: {player.level}") # Score: 0, Level: 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, השתמשו בתחביר פריקת tuple:
width, height = dimensions
- חשוב: ב-setter, השתמשו בתחביר פריקת tuple:
נסו בעצמכם
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 # לא tuple
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)
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםהפרמטר selfמתודותמאפייניםשיטת הבנאי (__init__)חזרה: מחשבון פשוט5פולימורפיזם
בחינה מחדש של דריסת מתודותטיפוסיות ברווזמחלקות ומתודות אבסטרקטיותעיצוב ממשקיםסיכום – מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה לעומת הורשהMixinsמתודות סטטיות ומתודות מחלקהדקורטורים למחלקותמנהלי הקשר6כימוס
איברים ציבוריים, מוגנים ופרטייםמשני גישההסתרת מידעדקורטורים מתקדמים של Propertyחזרה - מערכת רישומי תלמידים12פרויקט: ניהול ספרייה
סקירת הפרויקטמחלקות ספר ומשתמשמערכת השאלת ספריםיכולת חיפושממשק מנהלבדיקות ואינטגרציהתרגלו בעצמכם: קומפיילר Python אונליין