الوراثة وتعدد الأشكال
متكتبش نفس الكود مرتين لحاجات شبه بعض.
الوراثة (Inheritance)
في شركة، كل الموظفين ليهم اسم ومرتب. المدير موظف برضو، بس زيادة عليه إنه عنده فريق. بدل ما تكتب كلاس المدير من الأول، بتخليه يورث من كلاس الموظف وتضيف بس الحاجات الجديدة.
class Employee: def __init__(self, name, salary): self.name = name self.salary = salary def monthly_pay(self): return self.salary def describe(self): return f"{self.name} earns {self.monthly_pay():,} EGP" class Manager(Employee): # Manager inherits from Employee def __init__(self, name, salary, team_size): super().__init__(name, salary) # reuse the parent's __init__ self.team_size = team_size def monthly_pay(self): # override: change parent behavior bonus = self.team_size * 500 return self.salary + bonus staff = [Employee("Omar", 12000), Manager("Nour", 25000, team_size=6)] for person in staff: print(person.describe())
parent الكلاس الأصلي، ويتقال له base class.child الكلاس اللي بيورث، ويتقال له subclass.super() بتنادي على نسخة الـ parent من الميثود.override إنك تكتب ميثود في الـ child بنفس الاسم عشان تغير سلوكها.لاحظ إن describe() مكتوبة مرة واحدة بس في Employee، ومع ذلك مع نور حسبت البونص. ده لأنها بتنادي self.monthly_pay()، و self هنا مدير، فبايثون استخدمت نسخة المدير.
تعدد الأشكال (Polymorphism)
الكلمة شكلها صعب بس الفكرة بسيطة: أوبجكتس مختلفة بترد على نفس الأمر كل واحد بطريقته. زي لما تقول لأي حد «ادفع»: واحد هيدفع كاش، وواحد فيزا، وواحد بمحفظة موبايل. انت مش فارق معاك هو هيدفع إزاي، المهم يدفع.
class Cash: def pay(self, amount): return f"Paid {amount} EGP in cash" class Card: def pay(self, amount): fee = amount * 0.01 return f"Paid {amount} EGP by card (+{fee:.0f} fee)" class MobileWallet: def __init__(self, number): self.number = number def pay(self, amount): return f"Paid {amount} EGP from wallet {self.number}" def checkout(method, total): # This function doesn't care WHICH payment type it gets print(method.pay(total)) for m in [Cash(), Card(), MobileWallet("010xxxxxxx")]: checkout(m, 450)
pay وخلاص. دالة checkout مش هتتغير خالص. الكود بيكبر من غير ما يتكسر.التغليف (Encapsulation)
مش كل حاجة جوه الأوبجكت المفروض تتلعب فيها من برا. في بايثون العرف إن أي attribute بيبدأ بـ _ (زي _balance) معناه «ده للاستخدام الداخلي، متلمسوش مباشرة»، واستخدم الميثودز اللي الكلاس عاملها.
class Wallet: def __init__(self): self._balance = 0 # "internal" by convention def add(self, amount): if amount <= 0: raise ValueError("Amount must be positive") self._balance += amount def get_balance(self): return self._balance w = Wallet() w.add(200) print(w.get_balance())
raise بتطلّع خطأ بنفسك لما حاجة غلط تحصل. اللي بيستخدم الكلاس يقدر يمسكه بـ try / except زي ما اتعلمنا في المرحلة الأولى.