לדלג לתוכן

5.4 אנקפסולציה הרצאה

ממברים פרטיים _

  • ממברים פרטיים (private members) הם ממברים שאתה לא יכול לגשת אליהם.
  • בפייתון כל ממבר ששמו מתחיל עם _ הוא מוגדר כממבר פרטי.
  • הנה דוגמה למחלקה עם ממבר פרטי
    class Player:
        def __init__(self, speed):
            self.name = name
            self.speed = speed 
            self._position_x = 0  # A private member
    
        def walk_forward(self):
            self._position_x += self.speed
            self._print_location()
    
        def _print_location(self):  # A private member
            print(f"* player in {self._position_x} location")
    
    # Good code - accessing only public membera
    p = Player(speed=3) 
    p.walk_forward()
    print(p.speed)
    
    # Bad code - accessing private members
    print(p._position_x)
    p._print_location()
    
  • אפשר לראות שהממברים _position_x ו - _print_location הם ממברים פרטיים, ו - walk_forward ו - speed הם ממברים רגילים (ציבוריים).
  • מחוץ למחלקה אנחנו נגשים רק לממברים ציבוריים, אנחנו נגשים לממברים פרטיים רק בתוך המחלקה.
  • לא כמו שפות תכנות אחרות, פייתון לא פוקד עלייך חוסר גישה לממברים פרטיים מחוץ למחלקה אבל עדיין לעשות את זה נחשב קוד לא נכון, אז לא לעשות את זה כמו בדוגמה למעלה.
  • השימוש ב_ בשמות כדי לצור ממברים פרטיים הוא קונבנציה, זה הדרך שלנו כמתכנתים להודיע על ממבר שלא אמורים לגשת אילו מבחוץ.
  • פייתון סומך על המפתחים שלו שיעקבו אחרי קונבנציות כמו אלו.

אנקפסולציה - Encapsulation

  • מה אם נרצה לגשת לממבר הפרטי מחוץ למחלקה מסיבה כלשהי?
  • אנקפסולציה: אנחנו יכולים לצור פונקציות שמטרתן להביא גישה לממברים פרטיים.
    class MyClass:
        def __init__(self):
            self._private_variable = 42
    
        def get_private_variable(self):  # Getter method
            return self._private_variable
    
        def set_private_variable(self, value)  # Setter method
            if value != 0
                raise ValueError("Value cannot be zero!")
            self._private_variable = value
    
    # Outside the class
    obj = MyClass()
    
    # Accessing private member through a public method (following convention)
    print(obj.get_private_variable())
    obj.set_private_variable(5)
    print(obj.get_private_variable())
    
  • למה? לפעמים אנחנו רוצים לתת למתכנת גישה למשתנה הפרטי שלנו פשוט עם הגבלות מסויימות, ניתן לעשות את זה עם עטיפות של מתודות שאנחנו כותבים.
  • מתודת get (getter) - מתודה שמאפשרת גישה לערך של ממבר פרטי.
  • מתודת set (setter) - מתודה שמאפשרת גישה לשנות את הערך של ממבר פרטי.
  • ניתן לראות בדוגמה למעלה שיש לנו משתנה פרטי בשם _private_variable ואנחנו מאפשרים גישה חופשית לערך שלו באמצעות getter, ומאפשרים גישה לערוך אותו כל עוד לא נותנים לו את הערך 0, באמצעות setter.

פרופרטי - Property decorator

  • דרך פייתונית לעשות getter ו - setter זה באמצעות הדקורטור property
    class TemperatureConverter:
        def __init__(self, celsius):
            self._celsius = celsius
    
        @property
        def celsius(self):
            return self._celsius
    
        @celsius.setter
        def celsius(self, value):
            if value < -273.15:
                raise ValueError("Temperature cannot be below absolute zero.")
            self._celsius = value
    
        @property
        def fahrenheit(self):
            return (self._celsius * 9/5) + 32
    
    
    temperature = TemperatureConverter(25)
    temperature.celsius = 30  # Using the setter method
    print(f"Celsius: {temperature.celsius}")
    print(f"Fahrenheit: {temperature.fahrenheit}")
    
  • עם property גם אפשר להגדיר getter ו- setter בצורה יותר יפה, וגם המתכנת יכול לגשת לממבר הפרטי כיאלו הוא ציבורי במקום לקרוא לפונקציות של getter ו - setter. ממש קסם!

דאטה קלאס - Dataclass

  • בפייתון המון פעמים אנחנו נרצה לכתוב מחלקה שרק שומרת מידע כמו זו:
    class Point:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __repr__(self):
            return f"Point(x={self.x}, y={self.y})"
    
        def __eq__(self, other):
            if not isinstance(other, Point):
                return False
            return self.x == other.x and self.y == other.y
    
    # Example usage
    p1 = Point(1, 2)
    p2 = Point(1, 2)
    print(p1 == p2)  # Automatically compares attributes for equality
    print(p1)
    
  • זה לא כיף ויעיל לכתוב כל כך הרבה קוד רק כדי לשמור מידע, בשביל זה יש לנו דאטה קלאס!
  • דאטה קלאס זה דקורטור שאפשר להוסיף לקלאס שלנו כדי לצור קלאסים ששומרים מידע בפשטות יותר
    from dataclasses import dataclass
    
    @dataclass
    class Point:
        x: int
        y: int
    
    # Example usage
    p1 = Point(1, 2)
    p2 = Point(1, 2)
    print(p1.x)
    print(p1 == p2)  # Automatically compares attributes for equality
    print(p1)
    
  • דאטה קלאסים אוטמטית יוצרים את כל הmagic methods שצריך כדי לצור מחלקה פשוטה ששומרת מידע.
  • שימו לב: אפשר לראות שהגדרנו קלאס ששומרת שדות סטטים, אבל זה לא באמת יהיו שדות סטטים זה פשוט איך שמגדירים דאטה קלאס.
  • נקודה חשובה: יש עוד המון פיצ'רים לdataclass שלא הצגתי, מוזמנים לקרוא עליהם בתיעוד של dataclass באינטרנט - הצגתי רק את הפיצ'רים היותר חשובים.