سطح مقدماتی (Beginner Level)
مفهوم پلیمورفیسم (Polymorphism) یا «چندریختی» یکی از ستونهای اصلی برنامهنویسی شیگرا (OOP) است. این کلمه از ریشه یونانی به معنای "چندین شکل" گرفته شده است. در پایتون، این مفهوم به این معنی است که یک رابط (Interface) یا نام تابع یکسان، میتواند برای انواع مختلفی از اشیاء رفتار متفاوتی داشته باشد.
به زبان ساده: ما اهمیتی نمیدهیم شیء دقیقاً چیست، فقط اهمیت میدهیم که «چه کاری میتواند انجام دهد».
۱. پلیمورفیسم در توابع و عملگرهای داخلی
شما بدون اینکه بدانید، بارها از پلیمورفیسم استفاده کردهاید. تابع len() یا عملگر + نمونههای بارز آن هستند.
مثال اول: رفتار متفاوت +
عملگر جمع برای اعداد «جمع ریاضی» انجام میدهد، اما برای رشتهها «الحاق» (Concatenation) انجام میدهد.
مثال دوم: رفتار تابع len()
تابع len برای لیست، رشته و دیکشنری کار میکند، با اینکه ساختار داخلی آنها کاملاً متفاوت است.
۲. پلیمورفیسم با متدها (Method Overriding)
در ارثبری، کلاس فرزند میتواند متدی که از کلاس والد به ارث برده را بازنویسی (Override) کند تا رفتار مخصوص به خود را داشته باشد. این رایجترین شکل چندریختی در OOP است.
مثال اول: حیوانات مختلف
در اینجا متد speak در هر کلاس رفتار متفاوتی دارد، اما ما همه آنها را با یک نام صدا میزنیم.
مثال دوم: اشکال هندسی
هر شکل فرمول مساحت مخصوص به خود را دارد، اما متد area() نام یکسانی دارد.
سطح پیشرفته (Professional Level)
در سطح حرفهای، پلیمورفیسم در پایتون فراتر از ارثبری ساده کلاسیک است. پایتون به عنوان یک زبان پویا (Dynamic)، به شدت بر Duck Typing تکیه دارد و ابزارهای قدرتمندی مانند ABC و Protocol را برای کنترل دقیقتر ساختارها ارائه میدهد.
۱. مفهوم Duck Typing
در پایتون جمله معروفی وجود دارد:
"اگر شبیه اردک راه میرود و شبیه اردک کوککوک میکند، پس اردک است."
در Duck Typing، نوع کلاس شیء مهم نیست؛ مهم این است که آیا متد یا ویژگی مورد نظر را دارد یا خیر. این یعنی برای پلیمورفیسم حتماً نیاز به ارثبری (Inheritance) نداریم.
مثال: کلاسهای غیرمرتبط
در مثال زیر، Car و Person هیچ ارتباط ارثبری با هم ندارند، اما چون هر دو متد move را دارند، در یک حلقه پلیمورفیک کار میکنند.
۲. استفاده از Abstract Base Classes (ABC)
برای ایجاد ساختارهای صلبتر و اطمینان از اینکه کلاسهای فرزند حتماً متدهای خاصی را پیادهسازی میکنند، از ماژول abc استفاده میکنیم. این کار نوعی "قرارداد" (Contract) ایجاد میکند.
from abc import ABC, abstractmethod
class PaymentGateway(ABC):
@abstractmethod
def pay(self, amount):
pass
class PayPal(PaymentGateway):
def pay(self, amount):
print(f"Paying {amount}$ via PayPal")
# class Stripe(PaymentGateway):
# pass
# Error: Stripe must implement 'pay' method
۳. پلیمورفیسم تابعی (Function Dispatching)
گاهی نیاز داریم یک تابع بر اساس نوع آرگومان ورودی، رفتار متفاوتی داشته باشد. به جای نوشتن زنجیرهای از if/else و isinstance، میتوانیم از دکوریتور @singledispatch از ماژول functools استفاده کنیم.
مثال: پردازش دادههای مختلف
این روش تمیزترین راه برای پیادهسازی Overloading در توابع پایتون است.
۴. پروتکلها (Static Duck Typing)
از پایتون ۳.۸ به بعد، ماژول typing.Protocol معرفی شد. این قابلیت به ابزارهای Type Checker (مثل MyPy) اجازه میدهد تا پلیمورفیسم را بدون نیاز به ارثبری چک کنند.
from typing import Protocol
class Flyer(Protocol):
def fly(self) -> None:
...
class Bird:
def fly(self):
print("Bird flying")
class Airplane:
def fly(self):
print("Plane flying")
def launch(obj: Flyer):
obj.fly()
# Both work and pass static type checking
launch(Bird())
launch(Airplane())