چندریختی (Polymorphism)، یکی از ارکان اصلی برنامهنویسی شیءگرا (OOP)، این امکان را فراهم میکند که اشیاء از کلاسهای مختلف بتوانند به یک فراخوانی متد واحد، به روش مخصوص به خود پاسخ دهند. در اصل، چندریختی یعنی داشتن «اشکال یا فرمهای گوناگون».
در پایتون، به دلیل نوعدهی پویا (Dynamic Typing) و Duck Typing، چندریختی بسیار انعطافپذیر و قدرتمند است.
اصول اصلی:
بازنویسی متد (Method Overriding):
- رایجترین نوع چندریختی است.
- کلاس مشتق (فرزند)، پیادهسازی خودش را از متدی ارائه میدهد که قبلاً در کلاس پایه (والد) تعریف شده است.
- زمانی که متد روی شیء کلاس مشتق فراخوانی شود، نسخه کلاس مشتق اجرا خواهد شد.
شبیهسازی بارگذاری متد (Method Overloading):
- پایتون برخلاف زبانهایی مانند C++ یا Java از بارگذاری سنتی متد پشتیبانی نمیکند.
- اما میتوان این قابلیت را با استفاده از آرگومانهای پیشفرض، آرگومانهای متغیر (
*args
,**kwargs
) و منطق شرطی شبیهسازی کرد. - این روش امکان اجرای یک متد را با آرگومانهای مختلف فراهم میکند.
Duck Typing:
«اگر مثل اردک راه برود و مثل اردک صدا دهد، پس اردک است!»
- در Duck Typing، پایتون به رفتار شیء توجه میکند نه نوع آن.
- اگر شیء متدها و ویژگیهای لازم را داشته باشد، صرفنظر از اینکه از کدام کلاس آمده، قابل استفاده است.
- این نوعی چندریختی ضمنی (Implicit Polymorphism) است.
مثال Method Overriding:
class Animal:
def speak(self):
print("Animal sound")
class Dog(Animal):
def speak(self): # بازنویسی متد speak()
print("Woof!")
class Cat(Animal):
def speak(self): # بازنویسی متد speak()
print("Meow!")
def animal_sound(animal):
animal.speak()
my_dog = Dog()
my_cat = Cat()
animal_sound(my_dog) # اجرای speak از کلاس Dog
animal_sound(my_cat) # اجرای speak از کلاس Cat
در این مثال، تابع animal_sound
میتواند اشیائی از کلاسهای مختلف (Dog, Cat) را بپذیرد، مشروط به اینکه متد speak()
را داشته باشند. این همان چندریختی در عمل است.
شبیهسازی Method Overloading:
class Calculator:
def add(self, a, b=None, c=None):
if c is not None:
return a + b + c
elif b is not None:
return a + b
else:
return a
calc = Calculator()
print(calc.add(5)) # ۵
print(calc.add(5, 10)) # ۱۵
print(calc.add(5, 10, 15)) # ۳۰
class Formatter:
def format_text(self, *args):
if len(args) == 1:
return str(args[0]).upper()
elif len(args) == 2:
return f"{args[0]}: {args[1]}"
else:
return "Too many arguments"
f = Formatter()
print(f.format_text("hello")) # خروجی: HELLO
print(f.format_text("Name", "John")) # خروجی: Name: John
print(f.format_text("a", "b", "c")) # خروجی: Too many arguments
در اینجا متدهای add()
و format_text()
چندشکلی رفتار میکنند و با تعداد مختلفی از آرگومانها سازگار هستند.
Duck Typing در عمل:
class Bird:
def fly(self):
print("Bird flying")
class Airplane:
def fly(self):
print("Airplane flying")
class Kite:
def fly(self):
print("Kite flying")
def make_it_fly(thing):
thing.fly()
bird = Bird()
plane = Airplane()
kite = Kite()
make_it_fly(bird)
make_it_fly(plane)
make_it_fly(kite)
در این مثال، تابع make_it_fly
اهمیتی نمیدهد که نوع شیء چیست؛ فقط بررسی میکند که آیا متد fly()
را دارد یا نه.
مزایای چندریختی:
- انعطافپذیری: امکان استفاده از اشیای مختلف بدون نیاز به دانستن نوع دقیق آنها.
- قابلیت گسترش: افزودن کلاسها و رفتارهای جدید بدون نیاز به تغییر کدهای موجود.
- نگهداری آسانتر: کاهش تکرار کد و سادهتر شدن توسعه و رفع اشکال.
- انتزاع (Abstraction): پنهانسازی جزئیات پیادهسازی، برای سادهسازی سیستمهای پیچیده.
- سازماندهی بهتر کد: افزایش ماژولار بودن کدها.
نکات مهم:
- استفاده بیشازحد از چندریختی، خصوصاً در سیستمهای بزرگ، میتواند باعث پیچیدگی بیش از حد و کاهش خوانایی کد شود.
- مهم است که از چندریختی به صورت منطقی و سازگار استفاده شود.
- اگرچه Duck Typing قدرتمند است، اما اتکا بیش از حد به آن ممکن است منجر به خطاهای زمان اجرا شود، بهویژه اگر شیء موردنظر متد مورد انتظار را نداشته باشد.
چندریختی یکی از ابزارهای بسیار قدرتمند در جعبه ابزار OOP پایتون است. استفاده صحیح و مؤثر از آن به شما امکان میدهد کدی انعطافپذیر، قابلاستفاده مجدد و نگهداریپذیر بنویسید که در برابر تغییرات و گسترش، مقاومتر باشد.