به کمک ارث بری در پایتون میتوانیم ویژگیها و رفتارهای یک کلاس را از کلاس بالاتر به ارث ببریم. مثلاً کلاس گربه از کلاس حیوان ارثبری میکند تا مجبور نباشیم همه عملکردها را مجدداً تعریف کنیم. در این آموزش نحوه ارثبری یا inheritance در پایتون را یاد میگیریم.
در اصول برنامه نویسی شی گرا یک بحث اساسی به نام ارثبری در کلاسها داریم. به کمک ارث بری یا inheritance ویژگیها و رفتارهای یک کلاس از کلاس بالاتر به ارث گرفته میشود.
دقیقاً همانطور که در تولیدمثل انسانها، فرزندان ویژگیها و رفتارهایی را از والدین خود به ارث میبرند. البته هر فرزند میتواند ویژگیها و رفتارهای منحصربهفرد خودش را نیز داشته باشد.
برای تطابق بهتر ارث بری در پایتون با دنیای واقعی، یک مثال کوچک دیگر میزنم. فرض کنید کلاسی به نام «Pet» داریم که حیوان خانگی ما است.
در اینصورت میتوان زیرکلاسهایی مثل گربه و سگ داشته باشیم. هر دوی آنها نوعی Pet هستند که علاوه بر دارا بودن ویژگیهای Pet، خصوصیتها و رفتارهای منحصربهفردی نیز دارند.
ارث بری در پایتون
همگی با تعریف کلاس در پایتون آشنا هستیم. برای اینکه یک کلاس از کلاس دیگری ارث بری کند، از پرانتز در جلوی نام کلاس استفاده میکنیم.
فرض کنید دو کلاس A و B داریم. میخواهیم B از Aارثبری کند، یعنی همه propertyها و methodهای آن را در خودش داشته باشد. برای این کار ساختاری مشابه زیر خواهیم داشت:
class A:
pass # class A body
class B(A):
pass # class B body
مثالی از ارث بری پایتون
برگردیم به آخرین مثالی که زدم. ابتدا یک کلاس به نام Pet برای حیوان خانگی در پایتون در نظر میگیریم. در سازندهی این کلاس، نام، رنگ و سن پت را تعریف میکنیم. همچنین دو متد داریم:
- متد
getName()
نام او را برمیگرداند. - متد
makeSound()
در حالت کلی یک متن بیربط را چاپ میکند. واضح است که صدای گربه و سگ متفاوت است. در جلوتر یاد میگیریم این متدها را برای هر کلاس مجدداً تعریف کنیم.
class Pet:
def __init__(self, name, color, age):
self.name = name
self.color = color
self.age = age
def getName(self):
return self.name
def makeSound(self):
print("bla bla bla")
به زبان خیلی ساده، متد تابعی است که در کلاس تعریف میشود و به واسطه شئ (object)های آن کلاس در دسترس خواهد بود. اگر به توابع تسلط ندارید، آموزش تابع در پایتون را ببینید.
حالا کلاس Cat را تعریف میکنم. یک متد ساده برای اینکه مشخص کنیم گربه در حال دنبال کردن موش است نیز در آن تعریف میکنم:
class Cat(Pet):
def chasingRat(self):
print("It's chasing rat!")
حالا یک نمونه (شئ) از گربه میسازم:
kitty = Cat("Kitty", "white", 2)
به کمک IDE بررسی میکنم که به چه متدها و ویژگیهایی روی این شیء دسترسی دارم:
همانطور که میبینید، هم میتوانم متدها و ویژگیهای کلاس Pet را استفاده کنم و هم کلاس Cat. این مسئله یعنی ارث بری در پایتون! 🙂
اگر دقت کنید، در هنگام ایجاد گربه نیز از سازنده کلاس والد (parent) استفاده شده است. در قطعه کد زیر، به متدهای مختلف آن دسترسی پیدا میکنم:
print(kitty.getName()) # Kitty
kitty.chasingRat() # It's chasing rat!
بازنویسی در کلاس فرزند
وقتی میخواهیم یک متد در کلاس والد را در کلاس فرزند (child) دوبارهنویسی کنیم، به آن Method Overriding گفته میشود. من میخواهیم متد makeSound()
را در کلاس Cat بازنویسی کرده و بدنه آن را تغییر دهم.
class Cat(Pet):
def chasingRat(self):
print("It's chasing rat!")
def makeSound(self):
print("meowwww!")
حالا اگر از کلاس Cat یک شئ ساخته و makeSound()
را صدا بزنیم، متد درون کلاس Cat اجرا خواهد شد. به همین سادگی توانستیم بازنویسی متد در هنگام ارث بری در پایتون را انجام دهیم.
kitty = Cat("Kitty", "white", 2)
kitty.makeSound()
در IDEهای مختلف، معمولاً توابعی که در هنگام ارثبری override میشوند را با علامت یا حتی تغییر رنگ مشخص میکنند. مثلاً در PyCharm در کنار نام متد، چنین علامتی قرار داده میشود:
نکات مهم ارثبری در پایتون
دیدید که به همین سادگی توانستیم بین دو کلاس ارثبری کنیم. بهتر است ۲ نکته بسیار مهم را نیز با هم مرور کرده و یاد بگیریم:
ارثبری چندگانه در پایتون
زبان پایتون از ارثبری چندگانه پشتیبانی میکند. یعنی هر کلاس میتواند همزمان از دو یا چند کلاس دیگر inheritance کند.
برای ارث بری چندگانه در پایتون، کافی است نام کلاسهای والد را با کاما (,
) جدا کرده و مشابه قبل عمل کنیم:
class A:
# body
class B:
# body
class C(A, B):
# body of C that inherited from A, B
دقت کنید که ترتیب این کلاسها اهمیت دارد. بررسی تأثیر ترتیب آنها از بحث این آموزش خارج است. اما در همین حد بدانید که اگر چند متد همنام در این کلاسها وجود داشته باشد، متدی که در سمت راستترین کلاس وجود دارد روی بقیه بازنویسی خواهد شد.
ارث بری سلسله مراتبی
احتمالاً تا اینجا حدس زدهاید که میتوانیم ارثبری متوالی در کلاسهای پایتون داشته باشیم. اگر مثال اصلی آموزش را در نظر بگیریم، حیوان خانگی خودش از کلاس حیوانات ارثبری کرده است. بنابراین میتوانیم ساختاری مشابه زیر نیز داشته باشیم.
برای اینکه کدها طولانی نشود، بدنه کلاسها را حذف کرده و از کلمه کلیدی pass استفاده کردهام.
کلاس والد در ارث بری پایتون
گاهی اوقات لازم است در کلاس فرزند، به متدهای کلاس والد دسترسی داشته باشیم. برای این کار دو روش داریم:
- استفاده از تابع
super()
برای دسترسی به کلاس والد - استفاده از نام کلاس والد و دسترسی به متدهای آن
فرض کنید میخواهم در سازنده Cat رنگ چشم گربه را نیز بگیرم. برای این کار میتوانم کل بدنه را بازنویسی کنم؛ یعنی مقداردهی همه متغیرها را مجدداً انجام دهم. همچنین میتوانم مشابه کد زیر، از سازنده Pet کمک بگیرم:
class Pet:
def __init__(self, name, color, age):
self.name = name
self.color = color
self.age = age
class Cat(Pet):
def __init__(self, name, color, age, eye_color):
super().__init__(name, color, age)
self.eye_color = eye_color
kitty = Cat("Kitty", "white", 2, "black")
اگر بخواهیم به روش دوم عمل کنیم، کلاس فرزند به حالت زیر تغییر میکند. دقت کنید که در این روش، مجبوریم self را به عنوان آرگومان ورودی به متدی که فراخوانی کردهایم بدهیم.
class Cat(Pet):
def __init__(self, name, color, age, eye_color):
Pet.__init__(self, name, color, age)
self.eye_color = eye_color
پیشنهاد میکنم همین الآن ۲ یا ۳ کلاس (متفاوت با مثالی که زدم) بنویسید و چند متد و ویژگی در آنها تعریف کنید. سعی کنید بین اینها ارث بری چندگانه برقرار کنید. اگر دوست داشتید، مستندات انگلیسی آن توضیحات متنی بیشتری درباره فرآیند ارثبری ارائه کرده است.