وراثت

وراثت به یک کلاس اجازه می‌دهد که خصوصیات یا متدهایی را از کلاس دیگر به ارث برد. وراثت مانند رابطه پدر و پسری می‌ماند به طوریکه فرزند خصوصیاتی از قبیل قیافه و رفتار را از پدر خود به ارث برده باشد.

همه متد و خصوصیات کلاس پایه می‌توانند در کلاس مشتق مورد استفاده قرار بگیرند. مفهوم اصلی وراثت در مثال زیر نشان داده شده است :

  1: class Parent:
  2:     def __init__(self, m):
  3:         self.message = m;
  4: 
  5:     @property
  6:     def Message(self):
  7:         return self.message;
  8: 
  9:     @Message.setter
 10:     def Message(self, value):
 11:         self.message = value;
 12: 
 13:     def ShowMessage(self):
 14:         print(self.message);
 15: 
 16: 
 17: class Child(Parent):
 18:     def __init__(self, m):
 19:         super().__init__(m);
 20: 
 21:         
 22: myParent = Parent("Message from parent.");
 23: myChild  = Child("Message from Child.");
 24: 
 25: myParent.ShowMessage();
 26: myChild.ShowMessage();
 27: 
 28: myParent.Message = "Modified message of the parent.";
 29: myParent.ShowMessage();
 30: 
 31: myChild.Message = "Modified message of the child.";
 32: myChild.ShowMessage();
Message from parent.
Message from Child.
Modified message of the parent.
Modified message of the child.

در این مثال دو کلاس با نامهای Parent (خطوط 14-1) و Child (خطوط 19-17) تعریف شده است. در کلاس Parent یک متغیر به نام message تعریف کرده ایم که هم می توانیم با استفاده از سازنده و خاصیت ها آن را مقدار دهی کنیم و هم این مقدار را با استفاده از متد ()ShowMessage چاپ کنیم. در خط 17 که موضوع اصلی این درس است، کلاس Child از کلاس Parent ارث بری کرده است:

class DerivedClass(BaseClass):

همانطور که در خط 17 مشاهده می کنید، براحتی می‌توان با قرار دادن پرانتز بعد از نام کلاس و سپس نوشتن نام کلاسی که از آن ارث بری می‌شود (کلاس پایه) این کار را انجام داد. در داخل کلاس Child هم یک سازنده ساده وجود دارد که یک آرگومان قبول می‌کند. وقتی از وراثت در کلاسها استفاده می‌کنیم، هم سازنده کلاس مشتق و هم سازنده پیشفرض کلاس پایه هر دو اجرا می‌شوند. اگر هنگام صدا زدن سازنده کلاس مشتق بخواهیم سازنده کلاس پایه را صدا بزنیم باید از کلمه متد از پیش تعریف شده ()super استفاده کنیم. نحوه صدا زدن سازنده کلاس پایه در کلاس فرزند به صورت زیر است:

super().__init__();

در کل این خط بدین معنی است که تمام کدهای بدنه سازنده کلاس پایه را می خواهم در کلاس فرزند داشته باشم. به مثال زیر توجه کنید:

  1: class Parent:
  2:     def __init__(self):
  3:         print("Parent Constructor!")
  4: 
  5: class Child(Parent):
  6:     def __init__(self):
  7:         print("Child Constructor!")
  8:         super().__init__();
  9:        
 10: myChild  = Child();
Child Constructor!
Parent Constructor!

در کل بالا در خط 8 سازنده کلاس پایه را در کلاس فرزند فراخوانی کرده ایم. در نتیجه وقتی در خط 10 یک شیء از کلاس فرزند ایجاد می کنیم، هم پیغام مربوط به سازنده خودش (خط 7) و هم پیغام مربوط به سازنده کلاس پایه (خط 3) چاپ می شود. به کد ابتدای درس بر می گردیم. همانطور که اشاره شد، در کلاس Parent یک متغیر به نام message تعریف کرده ایم که هم می توانیم با استفاده از سازنده و خاصیت ها آن را مقدار دهی کنیم و هم این مقدار را با استفاده از متد ()ShowMessage چاپ کنیم. در خطوط 22 و 23 دو شیء از دو کلاس می سازیم و سپس در داخل پرانتز هم دو رشته می نویسیم که در داخل سازنده ها به متغیر message اختصاص داده شوند. در نتیجه زمانی که متد ()ShowMessage را در خطوط 25 و 26 فراخوانی می کنیم، مقدار موجود در متغیر message مربوط به هر دو کلاس چاپ می شوند.

برای درک بهتر قضیه وراثت به این نکته توجه کنید که با ارث بری کلاس Child از Parent در خط 17، تمام خاصیت ها و متدهای کلاس Parent (خطوط 14-5) در کلاس Child هم قابل دسترسی هستند و مشکل ما فقط سازنده کلاس Parent و متغیر message بود که برای در استفاده از آنها در کلاس Child از متد ()super استفاده کردیم (خط 19). اگر کلاس دیگری بخواهد از کلاس Child ارث بری کند، باز هم تمام متدها و خواص کلاس Child که از کلاس Parent به ارث برده است را به ارث می‌برد. کد ابتدای درس را به صورت زیر اصلاح می کنیم:

  1: class Parent:
  2:     def __init__(self, m):
  3:         self.message = m;
  4: 
  5:     @property
  6:     def Message(self):
  7:         return self.message;
  8: 
  9:     @Message.setter
 10:     def Message(self, value):
 11:         self.message = value;
 12: 
 13:     def ShowMessage(self):
 14:         print(self.message);
 15: 
 16: 
 17: class Child(Parent):
 18:     def __init__(self, m):
 19:         super().__init__(m);
 20: 
 21: class GrandChild(Child):
 22:     pass
 23:         
 24: myParent = Parent("Message from parent.");
 25: myChild  = Child("Message from Child.");
 26: myGrandChild = GrandChild("Message from GrandChild.")
 27: 
 28: myParent.ShowMessage();
 29: myChild.ShowMessage();
 30: myGrandChild.ShowMessage();
 31: 
 32: print();
 33: 
 34: myParent.Message = "Modified message of the parent.";
 35: myParent.ShowMessage();
 36: 
 37: myChild.Message = "Modified message of the child.";
 38: myChild.ShowMessage();
 39: 
 40: myGrandChild.Message = "Modified message of the grandChild.";
 41: myGrandChild.ShowMessage();
Message from Parent class!

همانطور که در کد بالا مشاهده می کنید، چون کلاس GrandChild از کلاس Child ارث بری کرده است (خط 21) و کلاس Child با ارث بری از کلاس Parent به تمام متدهای و خاصیت های آن دسترسی دارد. در نتیجه این متدها به متد GrandChild هم منتقل می شوند. در پایتون وراثت چندگانه هم وجود دارد، یعنی یک کلاس می تواند به طور همزمان از چند کلاس ارث بری کند. دستور وراثت چندگانه به صورت زیر است :

class SubclassName(BaseClass1, BaseClass2, BaseClass3, ...):
    pass

به مثال زیر توجه کنید:

class A:
    def AMessage(self):
        print("Message from A.");

class B:
    def BMessage(self):
        print("Message from B.");

class C:
    def CMessage(self):
        print("Message from C.");

class D(A, B, C):
    pass

d = D();

d.AMessage()
d.BMessage()
d.CMessage()
Message from A.
Message from B.
Message from C.