לדלג לתוכן

5.5 הורשה הרצאה

הורשה - Inheritance

  • הורשה זה קונספט בסיסי בOOP שמאפשר למחלקה לרשת מאפיינים ממחלקה אחרת.
    דוגמה:
    class Animal:
        def __init__(self, name):
            self.name = name
    
    class Dog(Animal):
        def speak(self):
            return f"{self.name} says Woof!"
    
    class Cat(Animal):
        def speak(self):
            return f"{self.name} says Meow!"
    
    # Example usage
    dog = Dog("Buddy")
    cat = Cat("Whiskers")
    
    print(dog.speak())  # Output: Buddy says Woof!
    print(cat.speak())  # Output: Whiskers says Meow!
    
  • במקרה הזה ניתן לראות שהמחלקות Dog ו - Cat יורשים מהמחלקה Animal.
  • המתודה __init__ והשדה name של Animal עוברים בירושה לCat ו - Dog.
  • מה זה עוזר לנו? במקרה הזה אפשר לראות שקיצרנו את הקוד, במקום לממש פעמיים __init__ לשני המחלקות השתמשנו בהורשה.
  • טרמינלוגיה:
    • מחלקת Animal - מחלקת אב (parent class), מחלקת על (super class), base class
    • מחלקת Dog/Animal - מחלקת בת (child class), תת מחלקת (subclass), derived class

פולימורפיזם - Polymorphism

  • מה אם נרצה בכל זאת לכתוב מתודת __init__ במחלקת ילד שלנו? איך נעשה את זה?
    class Animal:
        def __init__(self, name):
            self.name = name
    
    class Dog(Animal):
        def __init__(self, name, speed):
            self.speed = speed
            super().__init__(name) 
    
        def speak(self):
            return f"{self.name} says Woof!"
    
    # Example usage
    dog = Dog("Buddy", 5)
    
  • נוכל לעשות את זה, רק קיימת בעיה, כאשר נעשה את זה אנחנו נדרוס את ה__init__ של המחלקת אב, אז אנחנו נרצה לפנות אלייה בתוך ה__init__ של המחלקת ילד שלנו. נעשה זאת עם הפונקציה המובנת super, פונקציה זו מביאה לנו גישה למחלקת אב.
  • הדריסה הזו של הממברים שעשינו נקרא פולימורפיזם: פולי - הרבה, מורף - קריאות = (הרבה קריאות לאותה מתודה)

קונספט: המחלקה object

  • בפייתון כל מחלקה יורשת מהמחלקה object, המחלקה הזו היא המחלקה הבסיסית ביותר בפייתון, כולם יורשים ממנה.
  • נוכל להוכיח זאת עם שימוש בפונקציה המובנית issubclass.
    class MyClass:
        pass
    
    print(issubclass(MyClass, object))  # Output: True
    
  • המחלקה object היא המחלקה הבסיסית ביותר בפייתון, היא מגדירה את כל המתודות קסם שקיימות בפייתון. כאשר אנחנו מיישמים מתודות קסם במחלקות שלנו - אנחנו בעצם דורסים את המתודות שמוגדרות במחלקה object.
  • חשוב להכיר את הקונספט הזה כדי להכיר את פייתון לעומק יותר, זה פחות ישמש אותנו בכתיבת קוד.

מחלקות אבסטרקטיות

מתודות אבסטרקטיות

  • לפעמים כשאנחנו כותבים מחלקת אב, אנחנו רוצים לחייב את כל המחלקות ילד שיורשים מהמחלקה ליישם איזשהי מתודה, זה נקרא "מתודה אבסטרקטית"
    from abc import abstractmethod, ABC  
    
    
    class Animal(ABC):  
        def __init__(self, name):  
            self.name = name  
    
        @abstractmethod  
        def speak(self):  
            pass  
    
    
    class Dog(Animal):  
        def __init__(self, name, speed):  
            self.speed = speed  
            super().__init__(name)  
    
        def speak(self):  
            return f"{self.name} says Woof!"  
    
    
    dog = Dog("Buddy", 5)
    
  • אנחנו יכולים להשתמש במודול המובנה בפייתון abc כדי לעשות import ל -abstractmethod ו - ABC שאנחנו יכולים להשתמש בהם כדי להגדיר מתודה אבסטרקטית, ניתן לראות למעלה איך עושים את זה.
  • שימו לב שאם Dog לא היה ממש את המתודה speak הייתה נזרקת שגיאה.
  • אז מפה מגיעה השאלה: למה שנרצה לחייב את מחלקת הבת לממש כל מיני מתודות?
  • תשובה: כדי למנוע דברים לא צפויים -> אני רוצה לדאוג שכל מתכנת (כולל אני) כאשר הוא יוצר מחלקה שיורשת מהמחלקה שאני מגדיר יהיה חייב ליישם מתודות מסויימות, כדי למנוע הפתעות.
  • איזה הפתעות? הנה דוגמה:
    dog = Dog()
    cat = Cat()
    mouse = Mouse()
    animals = [dog, cat, mouse]
    
    for animal in animals:
        animal.speak()
    

    בקוד הבא יצרנו 3 סוגים של חיות, הקוד הזה תלוי בכך שלכל החיות יש מתודה בשם speak, אם אין לאחת החיות את המתודה הקוד יזרוק שגיאה. במקרה הזה נרצה להשתמש במתודה אבסטרקטית כדי לדאוג שלכל סוגי החיות יהיה את המתודה speak

שדות אבסטרקטים

  • כמו מתודות אבסטרקטיות, נוכל לעשות גם שדות אבסטרקטים שהמחלקת בת תהיה חייבת לממש
    from abc import ABC, abstractproperty
    
    class Animal(ABC):
    
        @property
        @abstractproperty
        def speed(self):
            pass
    
    class Dog(Animal):
    
        def __init__(self, speed):
            self._speed_ = speed
    
        @property
        def speed(self):
            return self._speed
    
    my_dog = Dog(value=5)
    print(my_dog.speed)
    
  • ניתן לראות שאפשר לעשות אבסטרקציה לשדות ישירות עפ אנקפסולציה (property)

מחלקה אבסטרקטית

  • חשוב לציין: המחלקה Animal היא מחלקה אבסטרקטית, כי היא מחילה ממברים אבסטרקטים.
  • איי אפשר לצור אובייקטים חדשים ממחלקה אבסטרקטית, כי חלק מהשדות/מתודות שלהם לא קיימות (לא מייושמות)

ממשק - אינטרפייס - Interface

  • ממשק הוא מחלקה אבסטרקטית שכל הממברים שלה הם אבסטרקטים.
  • מתי נשתמש בממשקים? כאשר נרצה לחייב מחלקות לענות על רשימת חוקים, הממשק הוא רשימת מתודות שהמחלקה חייבת ליישם.

הבדלים בין מחלקה אבסטרקטית לממשק

  • מחלקה אבסטרקטית יכולה שיהיה לה מתודות רגילות ומתודות אבסטרקטיות.
  • כל הממברים של ממשק חייבים להיות אבסטרקטים.