وراثت یعنی «این چیز، نسخهٔ خاصتری از آن چیز است و بیشتر رفتارش را از همان میگیرد». قدرتش استفادهٔ دوباره است؛ خطرش قاطیشدن مسئولیتها در یک درخت عمیق و شکننده.
وراثت پایه
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("هر حیوانی باید صدای خودش را تعریف کند.")
def introduce(self):
return f"من {self.name} هستم."
class Dog(Animal):
def speak(self): # بازنویسی
return "واق واق"
class Cat(Animal):
def speak(self):
return "میو میو"
Dog همهٔ رفتار Animal را به ارث میبرد و فقط speak را بازنویسی میکند. متد مشترک introduce بدون تکرار کد در اختیار هر دو است.
super و همکاری سازندهها
وقتی فرزند سازندهٔ خودش را مینویسد، معمولاً باید سازندهٔ والد را هم صدا بزند تا حالت پایه ساخته شود:
class GuardDog(Dog):
def __init__(self, name, zone):
super().__init__(name) # ساخت حالت پایه
self.zone = zone
def speak(self):
return super().speak() + "!" # توسعهٔ رفتار والد، نه جایگزینی کامل
چندریختی و ارسال پویا
چندریختی یعنی «یک رابط، رفتارهای متفاوت»: کدی که با Animal حرف میزند، برای Dog و Cat بدون تغییر کار میکند چون پایتون در زمان اجرا متد واقعی همان شیء را پیدا میکند (ارسال پویا).
def morning_call(animals):
for animal in animals:
print(animal.introduce(), "میگوید:", animal.speak())
morning_call([Dog("رکس"), Cat("میشی")])
اشتباه رایج
برای چندریختی حتماً باید وراثت داشته باشیم.
تصحیح
در پایتون تایپایمنی اردکی (duck typing) هم چندریختی میسازد: هر شیئی که متد speak داشته باشد کار میکند، حتی بدون والد مشترک. وراثت فقط یکی از راههاست.
انتزاع واقعی: ABC
وقتی میخواهی «بودنِ» یک رابط را اجبار کنی (نه فقط مستندش کنی)، از کلاس پایهٔ انتزاعی استفاده کن:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
...
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
# Shape() → TypeError: نمیشود از کلاس انتزاعی نمونه ساخت
جاوا «اینترفیس» جدا دارد؛ پایتون ندارد و لازم هم ندارد: abc.ABC برای اجبار وراثتی و typing.Protocol برای قرارداد ساختاری (بدون وراثت) همان کار را تمیزتر انجام میدهند.
ترکیب در برابر وراثت
ساختن رفتار از شیءهای دیگر («دارد») بهجای ارثبردن («هست»). انعطافپذیرتر و کمکوپلتر از وراثت عمیق است.
قاعدهٔ عملی: فقط وقتی وراثت بزن که رابطهٔ «هست» واقعاً برقرار باشد (سگ یک حیوان است). اگر رابطه «دارد» یا «استفاده میکند» است (ماشین یک موتور دارد، نه اینکه یک موتور باشد)، ترکیب کن.
class Engine:
def start(self):
return "موتور روشن شد."
class Car: # ترکیب، نه وراثت از Engine
def __init__(self):
self.engine = Engine()
def start(self):
return self.engine.start() + " ماشین آماده است."
سنجش فهم — وراثت و چندریختی
۰ از ۳ پاسخ داده شده