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

آموزش Polymorphism در Python به زبان ساده

تا اینجا با مفاهیم مهم برنامه‌نویسی شی‌ءگرا مانند Class، Object، Method، Inheritance و Encapsulation آشنا شدیم.

حالا به یکی دیگر از مفاهیم مهم OOP یعنی Polymorphism یا چندریختی می‌رسیم.

چندریختی چیست؟

واژه Polymorphism از دو بخش تشکیل شده است: Poly به معنی «چند» و Morph به معنی «شکل».

در برنامه‌نویسی، چندریختی یعنی یک رابط یا متد بتواند در Objectهای مختلف رفتار متفاوتی داشته باشد.

به زبان ساده:

یک نام یا روش استفاده می‌تواند برای چند Object یکسان باشد، اما هر Object رفتار مخصوص خودش را داشته باشد.

یک مثال ساده

فرض کنید چند حیوان داریم و همه آن‌ها متدی به نام speak() دارند.

class Dog:

    def speak(self):
        print("Woof")


class Cat:

    def speak(self):
        print("Meow")


dog = Dog()
cat = Cat()

dog.speak()
cat.speak()

خروجی:

Woof
Meow

همان نام speak() در دو کلاس استفاده شده است، اما هر Object رفتار متفاوتی دارد.

چندریختی با یک تابع

یکی از نکات جالب این است که می‌توانیم تابعی بنویسیم که با Objectهای مختلف کار کند.

class Dog:

    def speak(self):
        print("Woof")


class Cat:

    def speak(self):
        print("Meow")


def animal_sound(animal):
    animal.speak()


dog = Dog()
cat = Cat()

animal_sound(dog)
animal_sound(cat)

خروجی:

Woof
Meow

تابع animal_sound() لازم نیست بداند Object دقیقاً از چه کلاسی ساخته شده است. فقط کافی است Object متد speak() را داشته باشد.

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

یکی از کاربردهای مهم چندریختی در کنار Inheritance یا وراثت است.

فرض کنید یک کلاس والد به نام Animal داریم.

class Animal:

    def speak(self):
        print("Animal sound")


class Dog(Animal):

    def speak(self):
        print("Woof")


class Cat(Animal):

    def speak(self):
        print("Meow")

در اینجا کلاس‌های Dog و Cat از Animal ارث‌بری کرده‌اند.

بازنویسی متد یا Method Overriding

وقتی کلاس فرزند یک متد موجود در کلاس والد را با رفتار جدید تعریف می‌کند، به این کار Method Overriding یا بازنویسی متد می‌گوییم.

class Animal:

    def speak(self):
        print("Some sound")


class Dog(Animal):

    def speak(self):
        print("Woof")


class Cat(Animal):

    def speak(self):
        print("Meow")


animals = [Dog(), Cat()]

for animal in animals:
    animal.speak()

خروجی:

Woof
Meow

حلقه فقط یک بار از speak() استفاده می‌کند، اما هر Object رفتار مخصوص خودش را اجرا می‌کند.

یک مثال واقعی‌تر

فرض کنید در یک برنامه پرداخت، روش‌های مختلف پرداخت داریم: کارت بانکی و کیف پول دیجیتال.

class CardPayment:

    def pay(self, amount):
        print(f"پرداخت {amount} تومان با کارت")


class WalletPayment:

    def pay(self, amount):
        print(f"پرداخت {amount} تومان با کیف پول")


def make_payment(payment_method, amount):
    payment_method.pay(amount)


card = CardPayment()
wallet = WalletPayment()

make_payment(card, 100000)
make_payment(wallet, 200000)

خروجی:

پرداخت 100000 تومان با کارت
پرداخت 200000 تومان با کیف پول
نکته مهم:

تابع make_payment() فقط می‌داند Object موردنظر متدی به نام pay() دارد. بنابراین لازم نیست برای هر روش پرداخت یک تابع جداگانه بنویسیم.

چندریختی و حلقه‌ها

چندریختی زمانی بسیار مفید می‌شود که بخواهیم با مجموعه‌ای از Objectهای مختلف کار کنیم.

class Dog:

    def speak(self):
        return "Woof"


class Cat:

    def speak(self):
        return "Meow"


class Cow:

    def speak(self):
        return "Moo"


animals = [Dog(), Cat(), Cow()]

for animal in animals:
    print(animal.speak())

خروجی:

Woof
Meow
Moo

Duck Typing در پایتون

پایتون در بسیاری از موارد از روشی به نام Duck Typing استفاده می‌کند.

ایده اصلی آن این است که به جای اینکه فقط به نوع Object توجه کنیم، بررسی کنیم آیا Object رفتار یا متد موردنیاز را دارد یا نه.

مثال ساده:

اگر Object متد speak() را داشته باشد، می‌توانیم در کدی که به این متد نیاز دارد از آن استفاده کنیم؛ مهم نیست Object دقیقاً از چه کلاس مشخصی ساخته شده باشد.

مزایای چندریختی

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

  • Inheritance: برای ایجاد رابطه بین کلاس‌ها و به ارث بردن ویژگی‌ها و متدها استفاده می‌شود.
  • Polymorphism: اجازه می‌دهد Objectهای مختلف از یک رابط یا متد مشابه، رفتارهای متفاوتی داشته باشند.

تمرین عملی

سه کلاس به نام‌های Car، Motorcycle و Truck ایجاد کنید.

هر کلاس باید متدی به نام move() داشته باشد.

برای هر کلاس پیام متفاوتی چاپ کنید. سپس Objectهای هر سه کلاس را داخل یک لیست قرار دهید و با یک حلقه، متد move() را اجرا کنید.

جمع‌بندی

چندریختی یکی از مفاهیم مهم برنامه‌نویسی شی‌ءگرا است. با استفاده از آن می‌توانیم یک رابط یا متد مشابه را برای Objectهای مختلف استفاده کنیم، در حالی که هر Object رفتار مخصوص خودش را دارد.

در این درس یاد گرفتیم:

مرحله بعد: بعد از یادگیری مفاهیم اصلی OOP، در درس بعدی چند تمرین عملی را حل می‌کنیم تا مفاهیم Class، Object، __init__، Method، Inheritance، Encapsulation و Polymorphism را در کنار هم استفاده کنیم.