وراثت (inheritance)

وراثت (inheritance)

inheritance یا وراثت در پایتون

وراثت در پایتون قابلیتی است که به ما اجازه می دهد از تمامی خصوصیت ها و متدهای یک کلاس خاص، در کلاسی دیگر استفاده کنیم؛ نام وراثت هم از همین مسئله می آید، در واقع کدها را به ارث می بریم. فایده ی این قابلیت این است که دیگر نیازی به دوباره نوشتن کدها (مبحث reusability) و حجیم کردن برنامه ی خودمان نداریم، به همین خاطر سرعت کدنویسی ما بالاتر خواهد رفت. یادتان باشد که زمان عنصر اصلی برنامه نویس ها است!

کلاسی که کدهایش را برای کلاس دیگری به ارث می گذارد، کلاس پدر (parent class) و کلاسی که این کدها را به ارث می برد (از کدهای دیگران استفاده می کند) کلاس فرزند (child class) خوانده می شود.

برای ساخت کلاس پدر نیازی به انجام هیچ کار خاصی نیست و می توانیم به شکل یک کلاس عادی آن را تعریف کنیم:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

#Use the Person class to create an object, and then execute the printname method:

x = Person("John", "Doe")
x.printname()

در کد بالا کلاسی ساده داریم به نام Person. این کلاس دارای خصوصیات name (اسم کوچک) و lastname (فامیل) می باشد، همچنین یک متد به نام printname نیز دارد. از آنجایی که self به معنی شیء فعلی بود هر شیء ای که متد printname را صدا بزند نام و فامیل آن چاپ خواهد شد. این کلاس، یک کلاس پدر است.

حالا برای ساخت کلاس فرزند باید کلاس پدر را به عنوان پارامتر به آن پاس بدهیم (دقیقا مانند توابع). در مثال زیر یک کلاس به نام student ساخته ایم که خصوصیات و متدهای کلاس پدر را به ارث می برد:

class Student(Person):
  pass

نکته: زمانی که نمی خواهید هیچ خصوصیت یا متد دیگری به کلاستان اضافه کنید از کلیدواژه ی pass استفاده کنید.

حالا می توانیم به راحتی از خصوصیات و متدهای کلاس پدر (Person) در کلاس فرزند (student) استفاده کنیم:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  pass

x = Student("Mike", "Olsen")
x.printname()

همانطور که می بینید با کلاس student یک شیء به نام x ساخته ایم و سپس متد printname را روی آن صدا زده ایم (توجه کنید که چنین متدی در student وجود ندارد بنابراین از کدهای کلاس پدر استفاده شده است).

در حال حاضر کلاس فرزند کاملا خالی است و بهتر است به جای pass از تابع ()__init__ استفاده کنیم:

class Student(Person):
  def __init__(self, fname, lname):

اگر تابع ()__init__ را به کلاس student اضافه کنید، دیگر از تابع ()__init__ در کلاس پدر (person) استفاده نخواهد کرد و به نوعی وراثت ()__init__ باطل خواهد شد (البته بقیه ی کدها هنوز هم دارای وراثت خواهند بود). اگر به تابع ()__init__ درون کلاس پدر نیاز دارید باید آن را به شکل زیر صدا بزنید:

class Student(Person):
  def __init__(self, fname, lname):
    Person.__init__(self, fname, lname)

به طور مثال:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  def __init__(self, fname, lname):
    Person.__init__(self, fname, lname)

x = Student("Mike", "Olsen")
x.printname()

خروجی:

Mike Olsen

تابع ()super

استفاده از تابع ()super در زبان پایتون باعث می شود کلاس فرزند تمامی خصوصیات و متدهای کلاس پدر را به ارث ببرد. به این مثال دقت کنید:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  def __init__(self, fname, lname):
    super().__init__(fname, lname)

x = Student("Mike", "Olsen")
x.printname()

خروجی:

Mike Olsen

در واقع با استفاده از ()super دیگر نیازی به آوردن اسم پدر نیست.

اضافه کردن خصوصیات

فرض کنید می خواهیم یک خصوصیت جدید به نام graduationyear (سال فارغ التحصیلی) را به شیء student اضافه کنیم. در این حالت می گوییم:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  def __init__(self, fname, lname):
    super().__init__(fname, lname)
    self.graduationyear = 2019

x = Student("Mike", "Olsen")
print(x.graduationyear)

خروجی 2019 خواهد بود.

البته ما می توانیم با تغییر دادن تابع ()__init__ سال فارغ التحصیلی را همان اول به کلاس پاس دهیم:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  def __init__(self, fname, lname, year):
    super().__init__(fname, lname)
    self.graduationyear = year

x = Student("Mike", "Olsen", 2019)
print(x.graduationyear)

خروجی باز هم 2019 خواهد بود.

اضافه کردن متد

همانطور که قبلا هم گفتیم متدها در واقع توابعی هستند که درون یک کلاس قرار می گیرند. در مثال زیر می خواهیم یک متد به نام welcome به کلاس student اضافه کنیم:

class Person:
  def __init__(self, fname, lname):
    self.firstname = fname
    self.lastname = lname

  def printname(self):
    print(self.firstname, self.lastname)

class Student(Person):
  def __init__(self, fname, lname, year):
    super().__init__(fname, lname)
    self.graduationyear = year

  def welcome(self):
    print("Welcome", self.firstname, self.lastname, "to the class of", self.graduationyear)

x = Student("Mike", "Olsen", 2019)
x.welcome()

خروجی:

Welcome Mike Olsen to the class of 2019

نکته: اگر متدی در کلاس فرزند تعریف کنید که نام یکسانی با متدی در کلاس پدر داشته باشد، متد کلاس فرزند آن را override می کند (متد کلاس پدر برای کلاس فرزند باطل می شود).

سوال: آیا می توانیم از مبحث وراثت در کدهایمان استفاده نکنیم؟ آیا استفاده از آن اجباری است؟

پاسخ: وراثت یا inheritance چه در php و چه در زبان های برنامه نویسی دیگر از ابزارهای بسیار قوی کدنویسی محسوب می شود و فواید زیادی دارد (از جمله جلوگیری از مشکل code duplication یا نوشتن کدهای تکراری، کاهش زمان برنامه نویسی، افزایش سرعت، اشتباهات کمتر به دلیل تکرار نشدن کد و...). اگر شما از مبحث وراثت در کدهای خود استفاده نکنید باید هر کدی را که لازم داشتید، دوباره نویسی کنید که از نظر منطقی کاری بیهوده است. شاید در ابتدا این مبحث برایتان گیج کننده باشد اما با کمی تمرین به طور کامل بر آن مسلط خواهید شد.

امیدواریم از بحث وراثت در پایتون استفاده کافی را برده باشید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری از مقدماتی تا پیشرفته با پایتون توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

a azim
05 فروردین 1400
با تشکر فراوان....... برای این پست آموزشی...

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.