آموزش پایتون - وراثت چندگانه
وراثت یکی از ویژگیهای برنامهنویسی شیءگرا است که به یک کلاس اجازه میدهد ویژگیها و متدهای کلاس دیگری را به ارث ببرد. در پایتون، میتوانید انواع مختلفی از وراثت، مانند وراثت تکگانه، وراثت چندگانه و وراثت چندسطحی را پیادهسازی کنید. در این فصل، وراثت چندگانه را بهطور کامل بررسی میکنیم.
وراثت چندگانه چیست؟
وراثت چندگانه نوعی وراثت است که در آن یک کلاس میتواند ویژگیها و متدهای بیش از یک کلاس والد را به ارث ببرد. زمانی میتوان از این روش استفاده کرد که بخواهید قابلیتهای چندین کلاس را در یک کلاس واحد ترکیب کنید. تصویر زیر وراثت چندگانه را نشان میدهد:

مثالی از وراثت چندگانه
در مثال زیر، کلاس Child از هر دو کلاس Father و Mother ارثبری میکند:
class Father:
def skill1(self):
print("Father's skill: Gardening")
class Mother:
def skill2(self):
print("Mother's skill: Cooking")
class Child(Father, Mother):
pass
c = Child()
c.skill1()
c.skill2()
خروجی کد بالا به این صورت خواهد بود:
Father's skill: Gardening
Mother's skill: Cooking
توضیح: در این مثال، کلاس Child به هر دو متد skill1() و skill2() که از کلاسهای والد خود به ارث برده است، دسترسی دارد. هنگامی که یک نمونه از کلاس Child ایجاد میکنیم و متد skill1() را فراخوانی میکنیم، متد تعریفشده در کلاس Father اجرا میشود. به همین ترتیب، هنگام فراخوانی متد skill2()، متد تعریفشده در کلاس Mother اجرا خواهد شد.
اما اگر هر دو کلاس والد متدی با نام یکسان داشته باشند، چه اتفاقی میافتد؟ کدام متد اجرا خواهد شد؟ در اینجا ترتیب حل متدها (MRO) وارد عمل میشود.
ترتیب حل متدها در وراثت چندگانه
اگر متدهایی با نام یکسان در چند کلاس والد تعریف شده باشند، پایتون از ترتیب مشخصی پیروی میکند تا تصمیم بگیرد کدام متد را اجرا کند. این ترتیب با نام ترتیب حل متدها (MRO) شناخته میشود. این ترتیب با استفاده از الگوریتم خطیسازی C3 تعیین میشود که آن را الگوریتم MRO نیز مینامند. ترتیب MRO در ادامه آمده است.
- ابتدا، پایتون به دنبال متد موردنظر در خود کلاس فرزند میگردد.
- اگر متد پیدا نشود، کلاسهای والد را به ترتیبی که در تعریف کلاس فرزند فهرست شدهاند، بررسی میکند.
- این روند تا زمانی ادامه مییابد که متد پیدا شود یا تمام کلاسها بررسی شده باشند.
میتوانید ترتیب MRO یک شیء را با استفاده از متد mro() یا ویژگی __mro__ بررسی کنید. برای مثال:
print(Child.mro())
Output:
[<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Mother'>,
<class 'object'>]
مثال
در مثال زیر، کلاس Child متد skill() را از هر دو کلاس Father و Mother به ارث میبرد، اما متد کلاس پدر فراخوانی میشود.
class Father:
def skill(self):
print("Father's skill: Gardening")
class Mother:
def skill(self):
print("Mother's skill: Cooking")
class Child(Father, Mother):
pass
c = Child()
c.skill()
توضیح: هنگامی که متد skill روی نمونه c از کلاس Child فراخوانی میشود، پایتون ابتدا به دنبال این متد در کلاس Child میگردد. از آنجا که کلاس Child متد skill را ندارد، پایتون کلاسهای والد را به ترتیبی که فهرست شدهاند، بررسی میکند؛ ابتدا Father و سپس Mother. در نهایت، اولین متدی که پیدا کند اجرا میشود.
خروجی کد بالا به این صورت خواهد بود:
Father's skill: Gardening
استفاده از super() در وراثت چندگانه
تابع super() در کلاس فرزند برای فراخوانی یک متد از زنجیره وراثت استفاده میشود. اگر در وراثت چندگانه از super() داخل یک متد استفاده کنید، این تابع برای تعیین متدی که باید فراخوانی شود، دقیقاً از ترتیب MRO پیروی میکند.
مثال
در این مثال، یک سلسلهمراتب شامل چهار کلاس A، B، C و D داریم. کلاس D از هر دو کلاس B و C ارثبری میکند که نمونهای از وراثت چندگانه است.
class A:
def show(self):
print("Class A")
class B(A):
def show(self):
print("Class B")
super().show()
class C(A):
def show(self):
print("Class C")
super().show()
class D(B, C):
def show(self):
print("Class D")
super().show()
d = D()
d.show()
خروجی کد بالا به این صورت خواهد بود:
Class D
Class B
Class C
Class A
توضیح: ترتیب MRO برای کلاس D برابر با [D, B, C, A, object] است. این یعنی هنگامی که متدی روی یک نمونه از کلاس D فراخوانی میشود، پایتون ابتدا کلاس D، سپس B، بعد C و در نهایت A را بررسی میکند. بنابراین، عبارتهای "Class D"، "Class B"، "Class C" و "Class A" به همین ترتیب چاپ میشوند.
مشکل الماس در وراثت چندگانه
مشکل الماس یکی از مسائل رایج در وراثت چندگانه است. این مشکل زمانی به وجود میآید که دو کلاس والد از یک کلاس پایه مشترک ارثبری کنند و یک کلاس فرزند نیز از هر دو کلاس والد ارث ببرد. نمودار زیر این وضعیت را نشان میدهد:

مشکل الماس باعث سردرگمی درباره این موضوع میشود که وقتی کلاس فرزند متدی را از کلاس پایه به ارث میبرد، کدام نسخه از آن متد باید فراخوانی شود. پایتون این مشکل را با پیروی از ترتیب MRO (ترتیب حل متدها) که پیشتر بررسی کردیم، حل میکند. بیایید مثالی از مشکل الماس را ببینیم:
مثال
کد زیر مشکل الماس و نحوه حل آن توسط پایتون با استفاده از MRO را نشان میدهد:
class A:
def show(self):
print("Class A")
class B(A):
def show(self):
print("Class B")
class C(A):
def show(self):
print("Class C")
class D(B, C):
pass
d = D()
d.show()
خروجی کد بالا به این صورت خواهد بود:
Class B
توضیح: ترتیب MRO برای کلاس D برابر با [D, B, C, A] است. بنابراین، هنگامی که d.show() فراخوانی میشود، پایتون ابتدا کلاس D را بررسی میکند. از آنجا که تابع show در این کلاس پیدا نمیشود، به سراغ کلاس B میرود، تابع show را در آن پیدا میکند و اجرا میکند.
مزایا و معایب وراثت چندگانه
وراثت چندگانه چندین مزیت و عیب دارد:
| مزایا | معایب |
|---|---|
| ماژولار بودن و قابلیت استفاده مجدد از کد را بهبود میبخشد. | پیچیدگی را افزایش میدهد و ممکن است باعث ابهام شود. |
| امکان ترکیب قابلیتهای چندین کلاس را فراهم میکند. | ممکن است به مشکل الماس منجر شود. |
| امکان ایجاد روابط پیچیده در دنیای واقعی را فراهم میکند. | اشکالزدایی و نگهداری کد را دشوارتر میکند. |
جمعبندی
وراثت چندگانه مفهومی در برنامهنویسی شیءگرا است که به یک کلاس فرزند اجازه میدهد متدها را از چندین کلاس والد به ارث ببرد. در این درس بررسی کردیم که پایتون چگونه وراثت چندگانه را با استفاده از ترتیب حل متدها (MRO) مدیریت میکند و چگونه میتوان از تابع super() استفاده کرد. مشکل الماس یکی از مسائل رایج در وراثت چندگانه است، اما پایتون آن را با استفاده از MRO حل میکند. مهمترین عیب وراثت چندگانه این است که سلسلهمراتب کلاسها را پیچیدهتر میکند و درک آن را دشوارتر میسازد.
پیشرفت مطالعه: وضعیت خواندهشدن این درس فقط در همین مرورگر ذخیره میشود؛ بدون نیاز به حساب کاربری.