رفتن به محتوای اصلی
برنامه‌سازی پیشرفته با پایتون درس‌نامهٔ آزاد
درس متوسط ۲۵ دقیقه

وراثت و چندریختی

استفادهٔ دوبارهٔ امن از رفتار: وراثت، بازنویسی، ارسال پویا، super و انتخاب ترکیب در برابر وراثت.

هدف این درس

بتوانی سلسله‌مراتب وراثتی تمیز بسازی، رفتار را بازنویسی کنی و بگویی کِی ترکیب بهتر از وراثت است.

در این مطلب ۵

وراثت یعنی «این چیز، نسخهٔ خاص‌تری از آن چیز است و بیشتر رفتارش را از همان می‌گیرد». قدرتش استفادهٔ دوباره است؛ خطرش قاطی‌شدن مسئولیت‌ها در یک درخت عمیق و شکننده.

وراثت پایه

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() + " ماشین آماده است."

سنجش فهم — وراثت و چندریختی

۰ از ۳ پاسخ داده شده

  1. اگر فرزند __init__ خودش را بنویسد ولی super().__init__ را صدا نزند، چه می‌شود؟
  2. ماشین و موتور: وراثت یا ترکیب؟
  3. می‌توان مستقیم از یک کلاس ABC که متد انتزاعیِ پیاده‌نشده دارد نمونه ساخت.(درست / نادرست)

اول به همهٔ پرسش‌ها پاسخ دهید، بعد بررسی کنید.

مطالب مرتبط

از همین بخش و با برچسب‌های مشترک

این مطلب را خواندید؟ آن را علامت بزنید تا پیشرفت شما روی همین دستگاه ذخیره شود.

وضعیت پیشرفت برای وراثت و چندریختی