Kodax

الوراثة (Inheritance) — البرمجة الكائنية

الوراثة (Inheritance)

الوراثة تسمح بإنشاء صنف جديد يبني على صنف موجود: يأخذ كل خصائصه ودواله، ثم يضيف أو يغيّر ما يحتاجه.

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return "..."

class Cat(Animal):          # Cat يرث من Animal
    def speak(self):        # إعادة تعريف (override)
        return "مياو"

Cat("ميمي").name تعمل رغم أن Cat لم يعرّف __init__، لأنه ورثها.

العلاقة "هو نوع من" (is-a)

استخدم الوراثة عندما يكون الصنف الجديد نوعاً من الأب فعلاً: القطة حيوان، الحساب التوفيري حساب بنكي. إذا لم تصح الجملة، فالوراثة اختيار خاطئ (سنرى البديل في درس التركيب).

super(): استدعاء دالة الأب

عندما يحتاج الابن خصائص إضافية، يعرّف __init__ خاصة به ويستدعي __init__ الأب أولاً:

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)   # يهيئ name
        self.breed = breed

إذا نسيت super().__init__، لن تُنشأ الخاصية name وستحصل على AttributeError لاحقاً.

يمكنك أيضاً توسيع دالة الأب بدل استبدالها:

def describe(self):
    return super().describe() + f" من سلالة {self.breed}"

فحص الأنواع

rex = Dog("ريكس", "هاسكي")
isinstance(rex, Dog)       # True
isinstance(rex, Animal)    # True: الكلب حيوان أيضاً
issubclass(Dog, Animal)    # True

الوراثة المتعددة

Python تسمح بالوراثة من أكثر من صنف: class Duck(Animal, Swimmer). ترتيب البحث عن الدوال يسمى MRO ويمكن رؤيته بـ Duck.__mro__. استخدمها بحذر؛ الاستخدام الشائع والآمن هو أصناف صغيرة تضيف قدرة واحدة (تسمى mixins).

متى تكون الوراثة مشكلة؟

سلاسل وراثة عميقة (أ ← ب ← ج ← د) تجعل فهم مصدر كل سلوك صعباً. اجعل الهرم ضحلاً.

تمرين

أنشئ صنف Employee (الاسم، الراتب، annual_salary())، ثم Manager يرث منه ويضيف bonus ويعيد تعريف annual_salary() مستخدماً super().

# الصنف الأب
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def speak(self):
        return "صوت ما..."
    
    def info(self):
        return f"{self.name}, عمره {self.age} سنة"

# الصنف الابن
class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # استدعاء constructor الأب
        self.breed = breed
    
    # Override - إعادة تعريف
    def speak(self):
        return "هاو هاو! 🐕"
    
    def fetch(self):
        return f"{self.name} يجلب الكرة!"

class Cat(Animal):
    def speak(self):
        return "مياو! 🐱"
    
    def scratch(self):
        return f"{self.name} يخدش!"

# استخدام
dog = Dog("بادي", 3, "جولدن")
cat = Cat("ميمي", 2)

print(dog.speak())   # هاو هاو!
print(cat.speak())   # مياو!
print(dog.info())    # بادي, عمره 3 سنة
print(dog.fetch())

# التحقق من النوع
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Animal))  # True
print(issubclass(Dog, Animal))  # True

# Multiple Inheritance
class Flyable:
    def fly(self):
        return "أطير! ✈️"

class Swimmable:
    def swim(self):
        return "أسبح! 🏊"

class Duck(Animal, Flyable, Swimmable):
    def speak(self):
        return "كواك كواك! 🦆"

duck = Duck("دونالد", 1)
print(duck.speak())
print(duck.fly())
print(duck.swim())
اختبر فهمك