Menu
Coddy logo textTech

דקורטורים מתקדמים של 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 ושליטה מלאה בקבלת מאפיינים, בהגדרתם ובמחיקתם. כך נוצרים ממשקים אינטואיטיביים תוך שמירה על אימות נתונים חזק ועל אנקפסולציה.

challenge icon

אתגר

בינוני

באתגר הזה תממשו מחלקה בשם Rectangle עם כימוס תקין ואימות מאפיינים.

  • rectangle.py - זהו הקובץ שעליכם לערוך, והוא מכיל הערות TODO שינחו אתכם במימוש
  • driver.py - מכיל תרחישי בדיקה נרחבים (אין לשנות)
  1. ממשו מאפיינים פרטיים עבור _width ועבור _height
  2. צרו מאפיינים עבור width ועבור height עם אימות (הערכים חייבים להיות חיוביים)
    • העלו הודעות מתאימות מסוג ValueError כפי שמפורט בהערות TODO
    • חשוב: בדקו אם הערך קטן מ-0 או שווה לו, ואז העלו את השגיאה (כך תובטח התנהגות עקבית)
  3. ממשו מאפיינים לקריאה בלבד עבור area ועבור perimeter
  4. צרו מאפיין dimensions עם פונקציונליות של getter, setter ו-deleter, כפי שמתואר בהערות TODO
    • חשוב: ב-setter, השתמשו בתחביר פריקת tuple: width, height = dimensions

נסו בעצמכם

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}")
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Python אונליין