وراثت در پایتون – توضیح inheritance به زبان ساده – فرادرس

وراثت در پایتون – توضیح inheritance به زبان ساده – فرادرس


«وراثت» (Inheritance) مفهوم مهمی در «برنامه نویسی شی‌گرایانه» (Object-Oriented Programming | OOP) است که امکان خلق کلاس‌های جدید بر پایه کلاس‌های قبلی را فراهم می‌کند. پایتون نیز به عنوان یک زبان برنامه نویسی شی‌گرا از وراثت پشتیبانی می‌کند. بنابراین، درک انواع مختلف وراثت در پایتون جزء جدایی‌ناپذیر توسعه کدهای کارآمد و «قابل‌نگهداری» (Maintainable) است. ما سعی می‌کنیم در این مطلب از مجله فرادرس به شما کمک کنیم تا دید جامعی نسبت به وراثت در پایتون و انواع آن بدست بیاورید. در پایتون، وراثت به «زیرکلاس‌ها» (Subclasses) این امکان را می‌دهد که از «کلاس مرجع» (Superclass) خود، «متدها» (Methods) و «ویژگی‌ها» (Attributes) را به ارث ببرند. ایجاد کارآمدی به معنای استفاده مجدد از کدها هنگام تعریف کلاس‌های خاص‌تر است که بعضی از ویژگی‌ها و متدها را از کلاس والدشان ارث می‌برند.

پایتون انواع مختلفی از وراثت را پشتیبانی می‌کند که هرکدام ویژگی‌ها و کاربردهای خاص خود را دارند. قانون وراثت مشخص می‌کند که زیرکلاس چگونه از کلاس‌های مرجع خود ارث‌بری می‌کنند. بنابراین تعریف روابط بین کلاس‌ها و کدنویسی آن‌ها همیشه قابل گسترش است و انعطاف‌پذیر است. به‌طور کل در ادبیات فارسی و حتی قسمت عمده‌ای از متون انگلیسی به زیرکلاس‌ها، «کلاس فرزند» (Child Class) و به کلاس‌ها مرجع، «کلاس والد» (Parent Class) می‌گویند. در این مطلب هم از این به بعد به همین ترتیب نام می‌بریم. برای تولید کدهای قدرتمند و در عین حال منعطف، درک صحیح و کامل روش‌های وراثت بسیار ضروری است و با تسلط به چنین مهارتی، درصورت نیاز کدها به آسانی قابل گسترش یا اصلاح خواهند بود.

وراثت در پایتون چیست؟

وراثت در پایتون اشاره به فرایندی دارد که در طی آن یک کلاس فرزند، ویژگی‌ها و رفتارهای کلاس والد خود را به ارث می‌برد. با افزایش «تقسیم پذیری» (Modularity) و کارایی کدها، امکان «استفاده مجدد» (Re-use) و همچنین «گسترش» (Extension) کدها وجود دارد. افزایش پیدا می‌کند، می‌توان از کدها بصورت مجدد استفاده (Reusing) کرد و آن‌ها را «گسترش» (Extension) داد. کلاس والد به عنوان طرح اولیه برای کلاس‌های فرزند خود به‌کار می‌رود و ویژگی‌هایش را به کلاس‌های فرزند ارث می‌دهد، به کلاس‌های فرزند معمولا زیرکلاس (Subclass) یا «کلاس مشتق شده» (Derived Class) هم می‌گویند. بنابراین کلاس‌های فرزند این امکان را دارند که با فراهم بودن دسترسی به قابلیت‌هایی مثل متدها، متغیرها و اعضا در کلاس مرجع، از آن‌ها استفاده کنند یا حتی بر پایه آن‌ها قابلیت‌ها یا ويژگی‌های جدیدی برای خود بسازند.

پایتون «امکان دوباره استفاده کردن» (Reusability) از کدها را به وسیله وراثت، فراهم می‌کند. به توسعه‌دهندگان امکان می‌دهد به افزایش «تخصصی کردن» (Specialization) سطوح سلسله مراتب کلاس‌ها بپردازند. این کار اجازه ایجاد کلاس‌های فرزندی را می‌دهد که مشخصات عمومی تعریف شده در کلاس والد را به ارث می‌برند ولی دارای ویژگی‌های اختصاصی منحصر بفردی برای خود هستند. این مسئله باعث می‌شود که برنامه‌نویسان بجای اینکه کل کدهای کلاس‌های والد را تغییر بدهند و اصلاح کنند، روی اضافه کردن یا تغییر ویژگی‌ها درون کلاس‌های فرزند تمرکز کنند. علاوه بر این، وراثت امتیازهای بسیار خوبی ارائه می‌دهد که در ادامه نام می‌بریم.

  • امکان «کدنویسی ماژولار» (Modular Programming) را فراهم می‌کند.
  • امکان نگهداری از کدها را به‌صورت کارآمد فراهم می‌کند.
  • امکان به‌روزرسانی آسان در ویژگی‌ها و رفتارهای اشیا از طریق «پایگاه‌کد» (Codebase) وجود دارد.

نمونه کدی ساده برای تعریف وراثت

وراثت در پایتون تحقق رابطه «یک نوع از» (is-a) رو بین کلاس‌ها به آسانی ممکن می‌کند. برای مثال به کدی که در ادامه می‌آید توجه کنید.

class Vehicle: 
# attributes and methods for Vehicle 


class Car(Vehicle): 
# attributes and methods for Car, inheriting from Vehicle

کلاس Car زیرکلاسی از کلاس Vehicle است و ویژگی‌ها و متدهای خود را از کلاس Vehicle به ارث می‌برد. این رابطه ارث‌بری نسبت به کلاس پدر، ارتباط «یک نوع از» (is-a) را نشان می‌دهد، به این معنی که Car یک نوع از Vehicle است. کلاس فرزند ویژگی‌ها و رفتارهای خود را از کلاس والد، به ارث می‌برد و این باعث می‌شود، سیستمی عالی، برای ایجاد سلسه مراتب به صورت منطقی و منظم در کلاس‌ها بوجود آید.

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

  • ویژگی‌های وراثتی اصلاح شوند.
  • متد ها یا ویژگی‌های به ارث رسیده گسترش داده شوند.
  • متد ها یا ویژگی‌های به ارث رسیده به‌طور کل از اول «بازنویسی» (Overridden) شوند.

مزایای وراثت

وراثت در پایتون، مزایایی که در ادامه اشاره کرده‌ایم را فراهم می‌کند.

  • امکان «استفاده دوباره» (Reuse) آسان کدها
  • خوانایی بالاتر کدها
  • قابلیت نگهداری کدها
  • گروه‌بندی منطقی کلاس‌های مرتبط
  • سازماندهی بهتر «پایگاه‌کد» (Codebase)

استفاده از امکانات مضاعف وراثت برای توسعه‌دهندگان پایتون، به آن‌ها ابزار موثری جهت طراحی و سازماندهی برنامه‌های شی‌گرایانه، با انعطاف‌پذیری و مقیاس‌پذیری بیشتر می‌دهد.

به کمک امکانات مضاعف وراثت، توسعه‌دهندگان پایتون ابزار موثری جهت طراحی و سازماندهی برنامه‌های شی‌گرا دارند. این برنامه‌ها انعطاف‌پذیرتر هستند و مقیاس‌پذیری بیشتری دارند.

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

پایتون به یک عنوان زبان برنامه‌نویسی سطح بالای مفسری، از وراثت پشتیبانی می‌کند، این مسئله باعث «استفاده دوباره» (Reuse) کدها، «کاهش افزونگی» (Redundancy Reduction) و افزایش «قابلیت نگهداری» (Maintainability)‌ از کدها می‌شود. افزونگی به معنی تکرار کدها یا قطعاتی از سیستم است که حذف آن‌ها آسیبی به سیستم نمی‌رساند. و کاهش افزونگی برابر با افزایش بهره‌وری سیستم می‌شود.

در فهرست زیر، انواع وراست در پایتون آورده شده است که در ادامه توضیح مختصری در رابطه با هریک از آن‌ها آورده‌ایم.

  • «وراثت یگانه» (Single Inheritance)
  • «وراثت چندگانه» (Multiple Inheritance)
  • «وراثت چند سطحی» (Multilevel Inheritance)
  • «وراثت سلسله مراتبی» (Hierarchical Inheritance)
  • «وراثت ترکیبی» (Hybrid inheritance)

وراثت یگانه

وراثت یگانه در پایتون به زیرکلاس‌ها یا کلاس‌های مشتق شده اجازه می‌دهد که همه صفات و ویژگی‌ها را از یک کلاس والد به ارث ببرد. با پذیرش این نوع از وراثت، کلاس‌های فرزند به آسانی می‌توانند تمام قابلیت‌ها و ویژگی‌هایی که برای کلاس والدشان تعریف شده را کسب کنند بدون این‌که کدهای تکراری نوشته شوند. این نوع وراثت، حداکثر قابلیت استفاده مجدد از کد را فراهم می‌کند در حالی که به طور کامل مشکلات تکرار کد را از بین می‌برد.

مزایای وراثت یگانه

پیاده‌سازی وراثت یگانه به کلاس‌های مشتق شده اجازه می‌دهد تا از طریق ایجاد رابطه‌ی سلسله مراتبی، ارتباط مستقیمی با کلاس‌های والد خود برقرار کنند. این ارتباط کلاس‌های مشتق شده را قادر می‌سازد که از مزیت «پایگاه‌کد» (Codebase) موجود بهره‌مند شوند و از متدها، متغیرها و رفتارهای آن استفاده کنند. درنتیجه به توسعه‌دهندگان امکان می‌دهد در حالی که کلاس‌ها را به‌طور ویژه با نیازهای خاص برنامه، منطبق می‌کنند، به‌گسترش قابلیت‌های آن‌ نیز بپردازند.

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

وراثت یگانه با تشویق ساختار سلسله مراتبی کلاس‌ها، می‌تواند، «پایگاه‌کد» (Codebase) منظم و قابل مدیریتی بنا کند. توسعه‌دهندگان با جای‌گذاری کلاس‌ها در روابط والد-فرزندی می‌توانند سلسله مراتب وراثتی را پایه‌گذاری کنند که نمایان‌گر تمام روابط بین کلاس‌ها و وابستگی‌های متقابل آن‌ها به‌یکدیگر باشد. درنتیجه در حالی که خطایابی کدها آسانتر می‌شود، خوانایی، قابلیت نگهداری و «ماژولاریته» (Modularity) کدها هم افزایش پیدا می‌کند.

وراثت یگانه همچنین با حذف کدهای تکراری، اصل «خودت را تکرار نکن» (Don’t Repeat Yourself – DRY) را ترویج می‌دهد. از آنجا که کلاس‌های فرزند مشخصات و رفتارها را از کلاس والد خود به ارث می‌برند، توسعه‌دهندگان دیگر مجبور نیستند که توابع تکراری را در چندجای مختلف دوباره‌نویسی کنند، درعوض برای بدست آوردن بیشترین حالت بازدهی، کاهش احتمال خطا و فرایند آسانتر توسعه کدها، آن‌ها می‌توانند عملکردهای عادی کلاس را یک‌بار در کلاس والد پیاده‌سازی کنند و هروقت که نیاز شد از آن‌ها در زیرکلاس‌ها استفاده کنند.

نمونه کد ساده‌ای برای تعریف وراثت یگانه

قطعه کد زیر به سادگی ارث بری یک کلاس فرزند را از یک کلاس والد، یعنی ارث بری یگانه را نمایش می‌دهد.

class Parent:
     def func1(self):
          print("this is function one")
class Child(Parent):
     def func2(self):
          print(" this is function 2 ")
ob = Child()
ob.func1()
ob.func2()

می‌بینید که از کلاس فرزند شی ob

 را ساختیم. به آسانی به متد func1()

 که درون کلاس والد است دسترسی داریم و می‌توانید آن متد را فراخوانی کنیم. همچنین متد func2()

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

وراثت چندگانه

وراثت چندگانه نوعی از وراثت در پایتون است، به‌این صورت که یک کلاس فرزند از چندین کلاس والد ارث بری می‌کند و در نتیجه به خصوصیات و متدهای همه والدینش دسترسی دارد. وراثت چندگانه، یکی از ویژگی‌های کلیدی پایتون است در حالی که توسط کلاس‌ها در «جاوا» (Java) پشتیبانی نمی‌شود.

وراثت چندگانه مزایای زیادی برای ایجاد مدل‌های پیچیده ارائه می‌دهند. به عنوان نمونه، یکی از مزیت‌ها توانایی ترکیب کردن قابلیت‌های عملکردی چندین کلاس جداگانه در یک کلاس است. این ویژگی، بخصوص در زمان جمع‌آوری ویژگی‌های چندین کلاس در یک کلاس جدید، مفید خواهد بود. برای نمونه، اگر دو کلاس برای تعریف ویژگی‌های اشکالی با رنگ‌های مختلف داشته باشیم – مانند کلاسی برای ویژگی‌های شکل هندسی در مقابل کلاسی برای تعریف رنگ‌ها – با استفاده از وراثت چندگانه می‌توانیم این ویژگی‌ها را ترکیب کنیم و کلاس جدیدی تولید کنیم که هردو ویژگی را در یکجا داشته باشیم.

اگرچه، وراثت چندگانه می‌تواند پیچیده‌گی و ابهام نیز تولید کند. این مورد به‌ویژه زمانی رخ می‌دهد که ویژگی‌ها و متدهای متناقضی بین کلاس‌های والد، وجود داشته باشند. در چنین موقعیت‌هایی برای جلوگیری از گمراهی باید از نام‌گذاری مناسب قاعده‌ها یا بازنویسی متدها استفاده شود.

برای پیاده‌سازی وراثت چندگانه در پایتون، تمامی کلاس‌های والد را داخل تعریف کلاس فرزند لیست می‌کنیم – یعنی زمان تعریف کلاس، جلوی نام کلاس و داخل علامت‌های پرانتز – و با کاما ،

  از هم جدا می‌کنیم. وقتی نمونه‌ای از کلاس فرزند، ویژگی یا متدی را فراخوانی کند، در حالی که چندین کلاس والد هم برای آن وجود دارد، پایتون در ابتدا داخل کلاس فرزند را جستجو می‌کند، سپس داخل هر کلاس والد را – برعکس ترتیبی که لیست کردیم، یعنی از راست به چپ – جست و جو می‌کند. اگر چندین والد دارای متدها یا ویژگی‌های شبیه هم و با نام‌های دقیقا همسان باشند، پایتون از هرکدام که اول در صف – طبق نظم مورد نظر خودش که در جمله قبل اشاره کردیم – پیدا کند استفاده می‌کند.

نمونه کد برای تعریف وراثت چندگانه

در ادامه نمونه‌ای از تعریف کلاس چندگانه را در پایتون مشاهده می‌کنید.

class Parent:
   def func1(self):
        print("this is function 1")
class Parent2:
   def func2(self):
        print("this is function 2")
class Child(Parent , Parent2):
    def func3(self):
        print("this is function 3")
 
ob = Child()
ob.func1()
ob.func2()
ob.func3()

کلاس Child()

  از کلاس‌های Parent

 و Parent2

 ارث‌بری کرده است و طبیعتا به متدهای داخل خود و کلاس‌های والد خود دسترسی مستقیم دارد و می‌شود آن‌ها را فراخوانی کرد.

وراثت چند سطحی

در پایتون، وراثت‌ چندسطحی این اجازه را به کلاس‌های فرزند می‌دهد که از چندین لایه کلاس والد ارث‌بری کنند، که به نوبت خودشان از کلاس والد دیگری ارث‌بری کرده‌اند. این مسئله تضمین می‌کند که ویژگی‌های کلاس اصلی به تمام سطوح وراثتی منتقل شود، به کلاس فرزند یا هر نسل دیگری که در آینده از آن‌ها مشتق شود. این روش همچنان اطمینان می‌دهد که ویژگی‌های اصلی به همه اولاد احتمالی آینده کلاس حاضر، نیز منتقل شوند.

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

وراثت‌چندسطحی، ویژگی بسیار قدرتمندی در برنامه‌نویسی شی‌گرایی است که تکرار در کدها را کاهش می‌دهد و قابلیت دوباره استفاده کردن از کدهارا افزایش می‌دهد. با کمک ارث‌بری ویژگی‌ها از چندین کلاس، توسعه‌دهندگان می‌توانند به سرعت و با حداقل زحمت، سیستم‌های نرم‌افزاری پیچیده‌ای را بسازند. اگرچه، استفاده اشتباه از آن می‌تواند منجر به مشکل غیر قابل حلی در کدها شود که برای حفظ عملکرد سیستم در حالت بهینه، نیازمند تلاش دائمی برای نگهداری سیستم شود.

وراثت چندسطحی مزایای زیادی به توسعه‌دهندگان برای تولید کلاس‌های اختصاصی منطبق با موارد کاربردی خاص، می‌دهد. کلاس والد می‌تواند شامل ویژگی‌ها و رفتارهای عمومی شود که در موارد مختلف قابل استفاده است. کلاس مشتق شده از کلاس والد، می‌تواند این ویژگی‌های عمومی را به ارث ببرد در حالی که ویژگی‌های سفارشی خود را اضافه می‌کند. ویژگی‌هایی که به‌طور خاص برای کاربردی خاص استفاده می‌شوند. کلاس‌های مشتق شده بعدی می‌توانند از این کلاس‌ها و والدینشان ارث‌بری کنند و حتی برای خود یا ادامه نسل خود، ویژگی‌های اختصاصی بیشتری را اضافه کنند.

نمونه کد برای تعریف وراثت چندسطحی

در ادامه با یک مثال ساده، کد مربوط به وراثت چندسطحی را به شما نمایش می‌دهیم.

class Parent:
      def func1(self):
          print("this is function 1")
class Child(Parent):
      def func2(self):
          print("this is function 2")
class Child2(Child):
      def func3("this is function 3")
ob = Child2()
ob.func1()
ob.func2()
ob.func3()

در کد بالا، کلاس Parent

 ، کلاس مرجع ما است. کلاس Child

  از آن ارث‌بری می‌کند و کلاس Child2

 از کلاس Child

 ارث‌بری می‌کند. توجه کنید که شی ساخته شده از کلاس Child2

 به تمام متدهای سلسله کلاس‌های خود دسترسی دارد.

وراثت سلسله مراتبی

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

این مدل وراثتی، چیدمانی از سلسله مراتب را به نمایش می‌گذارد، به‌ این صورت که کلاس والد در بالا قرار می‌گیرد و کلاس‌های فرزند در زیر آن قرار می‌گیرند. در حالی که تمام صفات و ویژگی‌ها را به خوبی هر کلاس مشتق شده دیگری، از کلاس والد خود ارث بری می‌کنند.این نوع از وراثت به‌طور معمول زمانی استفاده می‌شود که چندین کلاس مشتق شده باید ویژگی‌ها یا عملکردهای یکسانی داشته باشند.

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

نمونه کد برای تعریف وراثت سلسله مراتبی

در ادامه با مثالی ساده معماری وراثت سلسله‌مراتبی را نمایش می‌دهیم.

class Parent:
      def func1(self):
          print("this is function 1")
class Child(Parent):
      def func2(self):
          print("this is function 2")
class Child2(Parent):
      def func3(self):
          print("this is function 3")
 
ob = Child()
ob1 = Child2()
ob.func1()
ob.func2()

در مثال بالا هردو کلاس Child

  و Child2

 از کلاس Parent

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

وراثت ترکیبی

وراثت ترکیبی، نوع خاصی از وراثت است که به کاربر اجازه می‌دهد که کلاس‌ها را با ارث‌بری از چندین کلاس والد ایجاد کند. برعکس وراثت چندگانه، حداقل یکی از والدین در وراثت ترکیبی از نوع کلاس پایه نیست بلکه خودش مستقیم از یک کلاس دیگر مشتق شده است. بنابراین، بهترین استفاده از وراثت را ممکن می‌کند و نیازمندی‌های کد را که استفاده از وراثت چندگانه را ضروری ساخته، برآورده می‌کند.

وراثت ترکیبی انعطاف‌پذیری بسیار عالی را برای کدنویسی ارائه می‌دهد که باعث می‌شود توسعه‌دهندگان در زمان طراحی کلاس‌ها قادر باشند ویژگی‌های پیچیده را با کارایی بیشتری پیاده‌سازی کنند. استفاده از کلاس‌های مشتق شده‌ به‌عنوان کلاس والد در زنجیره وراثت، کمک می‌کند در حالی که کیفیت کدها ارتقا داده می‌شوند، تکرار در کدها به حداقل برسد. این نوع از وراثت همچنین، توسعه‌دهندگان را قادر می‌سازد ساختار سلسله مراتب کلاس‌ها را به‌طور دقیق منطبق بر نیازمندی‌های اپلیکیشن خود، طراحی کنند.

وراثت ترکیبی به توسعه‌دهندگان این امکان را می‌دهد که ویژگی‌های مختلف را از طریق چندین کلاس والد در هم ادغام کنند تا بتوانند کلاس‌هایی با سفارشی‌سازی بالا، طراحی کنند. استفاده از وراثت ترکیبی، اجازه می‌دهد که کلاس‌هایی، مناسب انجام وظایف پیچیده طراحی شوند در حالی که به آسانی، امکان گسترش آن‌ها با افزودن ویژگی‌های بیشتر فراهم است.

نمونه کد برای تعریف وراثت ترکیبی

در ادامه، قطعه کدی قرارداده‌ایم تا در حالت بسیار ساده طراحی وراثت ترکیبی را نمایش دهد.

class Parent:
     def func1(self):
         print("this is function one")
 
class Child(Parent):
     def func2(self):
         print("this is function 2")
 
class Child1(Parent):
     def func3(self):
         print(" this is function 3"):
 
class Child3(Parent , Child1):
     def func4(self):
         print(" this is function 4")
 
ob = Child3()
ob.func1()

در اینجا، کلکسیونی از انواع وراثت را مشاهده می‌کنید.

  • وراثت یگانه: کلاس Child

      از کلاس Parent

     ارث بری کرده است.

  • وراثت سلسه مراتبی: همه کلاس‌های Child

     و Child1

     و Child3

      از کلاس Parent

      ارث‌بری کرده‌اند.

  • وراثت چندگانه: کلاس Child3

      از کلاس Child1

      و Parent

      ارث‌بری کرده است.

  • وراثت چند سطحی: کلاس Child3

      از کلاس Child1

      ارث‌بری کرده است، که آنهم از کلاس Parent

      ارث‌بری می‌کند.

  • وراثت ترکیبی: ترکیب همه مدل‌های وراثت می‌شود وراثت ترکیبی.

و در آخر مشاهده می‌کنیم، برای شی که از کلاس Child3

  ایجاد می‌کنیم، متد func1()

  که در کلاس Parent

  ایجاد شده در دسترس است. اکنون که نسبت به مسئله وراثت در پایتون به دید کلی و نسبتا خوبی رسیدید، بهتر است با دو تکنیک پرکاربرد برای استفاده بهتر از وراثت نیز آشنا شوید.

  • تابع ()Super در پایتون
  • «بازنویسی متدها» (Method overriding) در پایتون

تابع Super در پایتون

در زبان برنامه‌نویسی پایتون از تابع ()super برای اشاره به کلاس والد – کلاس مرجع – استفاده می‌شود. به شما این امکان را می‌دهد که متدهایی که در کلاس مرجع تعریف شده‌اند را در کلاس فرزند، فراخوانی کنید و عملکرد به ارث رسیده از کلاس والد را شخصی‌سازی کنید و یا گسترش دهید.

علت استفاده از تابع super چیست؟

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

مزایای تابع super چیست؟

  • برای دست‌یابی به متدهای کلاس والد، نیازی نیست که نام کلاس والد را به خاطر بیاورید یا مشخص کنید. این تابع در هر دوحالت وراثت یگانه و چندگانه کار می‌کند.
  • این دستور، ماژولاریته و قابلیت دوباره استفاده کردن از کدها را طوری پیاده‌سازی می‌کند که نیاز نباشد که کل تابع مورد نظر را از اول بنویسید.
  • چون پایتون یک زبان برنامه‌نویسی پویا است، تابع ()super هم یک تابع پویا است، درست برعکس زبان‌های برنامه‌نویسی دیگر.

وراثت در پایتون بدون تابع super چگونه کار می‌کند؟

در مثال زیر، متد __init__

  در کلاس Emp

  دارای یک مشکل است. کلاس Emp

  از کلاس Person

  ارث‌بری کرده است، ولی در متد __init__

  کلاس Emp

 ، متد __init__

  از کلاس والد، فراخوانی نشده که ویژگی‌های name

  و id

  را مقداردهی اولیه کند.

# code
class Person:

	# Constructor
	def __init__(self, name, id):
		self.name = name
		self.id = id

	# To check if this person is an employee
	def Display(self):
		print(self.name, self.id)
	

class Emp(Person):
	
	def __init__(self, name, id):
		self.name_ = name

	def Print(self):
		print("Emp class called")

Emp_details = Emp("David", 103)

# calling parent class function
Emp_details.name_, Emp_details.name

خروجی به‌صورت زیر خواهد بود.

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in 
     24 
     25 # calling parent class function
---> 26 Emp_details.name_, Emp_details.name

AttributeError: 'Emp' object has no attribute 'name'

حل مشکل بالا با کمک تابع super در پایتون

در کد نوشته شده بالا، کلاس Emp

 به درستی از کلاس Person

 ارث‌بری می‌کند ولی لازم است در ادامه، اصلاحاتی را برروی کد اعمال کنیم. متد __init__

 از کلاس Emp

 الان به درستی متد __init__

 از کلاس والد را با استفاده از تابع ()super فراخوانی می‌کند.

# code
# A Python program to demonstrate inheritance

class Person:

	# Constructor
	def __init__(self, name, id):
		self.name = name
		self.id = id

	# To check if this person is an employee
	def Display(self):
		print(self.name, self.id)
	

class Emp(Person):
	
	def __init__(self, name, id):
		self.name_ = name
		super().__init__(name, id)

	def Print(self):
		print("Emp class called")

Emp_details = Emp("David", 103)

# calling parent class function
print(Emp_details.name_, Emp_details.name)

که به صورت زیر خروجی می‌دهد.

David David

درک متدهای ()super با __init__ در Python

در پایتون یک متد رزرو شده به نام __init__

 وجود دارد. که در برنامه‌نویسی شی‌گرایی به «سازنده» (Constructor) اشاره می‌کند. وقتی که این متد فراخوانی می‌شود، به کلاس این اجازه را می‌دهد که «ویژگی‌ها» (Attributes) خود را تعریف کند و مقدار دهی اولیه انجام دهد. در یک کلاس فرزند که ویژگی‌های خود را به ارث برده است، می‌توان از تابع super()

  برای ارجاع به کلاس والد استفاده کرد. تابع super()

  یک شی موقتی از کلاس والد برمی‌گرداند که به کلاس فرزند اجازه دسترسی به همه متدهای آن را می‌دهد.

بازنویسی متدها در پایتون

«بازنویسی متد» (Method Overriding) نه تنها برای وراثت در پایتون بلکه توانایی مهمی برای هر زبان برنامه‌نویسی شی‌گرایانه دیگری هم محسوب می‌شود. این ویژگی به کلاس فرزند امکان می‌دهد، برای متدی که از قبل توسط یکی از کلاس‌های مرجع تعریف شده است، پیاده‌سازی مد نظر خودرا اعمال کند. وقتی که متدی در کلاس فرزند با متدی در کلاس والد آن فرزند، نام مشابه، پارامترها یا امضای مشابه و «نوع خروجی» (Return Type) مشابه داشته باشد، آن‌گاه می‌گویند متد داخل کلاس فرزند از متد کلاس والد «بازنویسی» (Override) شده‌است.

کدام نسخه از متدهای بازنویسی شده، اجرا می شود؟

نسخه متد اجرا شده، توسط شیئی تعیین می‌شود که برای فراخوانی آن استفاده شده است. یعنی اگر متدی در کلاس‌های مختلف بازنویسی شده باشد، در صورتی که توسط یک شی فراخوانی شود، به صورتی اجرا می‌شود که در کلاس ایجاد شده از آن، بازنویسی شده است. اگر شی از کلاس والد برای فراخوانی متد استفاده شده باشد، پس نسخه موجود از متد در کلاس والد اجرا خواهد شد اما اگر شی از کلاس فرزند باشد که متد را فراخوانی می‌کند، درنتیجه نسخه بازنویسی شده متد، در کلاس فرزند اجرا خواهد شد. به عبارت دیگر، برای تعیین این‌که چه نسخه‌ای از متد «بازنویسی شده» (Overridden) اجرا شود به نوع شی فراخواننده متد، رجوع خواهد شد، «نه نوع متغیر مرجع» (Not The Type Of The Reference Variable).

نمونه ای از روش بازنویسی متد

‌‌در قطعه کد زیر مثال ساده‌ای از نحوه کار کرد بازنویسی متدها را برای وراثت در پایتون می‌بینید.

# Python program to demonstrate 
# method overriding 


# Defining parent class 
class Parent(): 
	
	# Constructor 
	def __init__(self): 
		self.value = "Inside Parent"
		
	# Parent's show method 
	def show(self): 
		print(self.value) 
		
# Defining child class 
class Child(Parent): 
	
	# Constructor 
	def __init__(self): 
		self.value = "Inside Child"
		
	# Child's show method 
	def show(self): 
		print(self.value) 
		
		
# Driver's code 
obj1 = Parent() 
obj2 = Child() 

obj1.show() 
obj2.show() 

که به صورت زیر خروجی می‌دهد.

Inside Parent
Inside Child

سوالات متداول

در ادامه به بعضی از سوالاتی که بیشترین تکرار پرسش را در بین برنامه‌نویسان جوان داشتند اشاره خواهیم کرد.

وراثت در پایتون چیست؟

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

هدف از وراثت در پایتون چیست؟

وراثت در پایتون ۲ هدف اصلی را ارائه می‌دهد.

  • قابلیت «استفاده چندباره از کدها» (Code Reuse)
  • «کاهش افزونگی» (Redundancy Reduction)

وراثت کمک می‌کند که توسعه‌دهندگان، کلاس‌هایی با ویژگی‌های اضافه یا رفتارهای تغییر یافته، اما شبیه به کلاس‌های موجود به‌سازند. این کار باعث صرفه‌جویی در زمان و منابع می‌شود، ماژولاریته و قابلیت نگهداری کد را نیز افزایش می‌دهد.

وراثت یگانه در پایتون چیست؟

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

وراثت چندگانه در پایتون چیست؟

وراثت چندگانه در پایتون، نوعی از وراثت است که درآن، یک کلاس از چندین کلاس والد مشتق شده در حالی که همه مشخصات و متدهای آن‌ها را به ارث می‌برد و می‌تواند هر ویژگی یا متدی که نیازداشته باشد را اضافه یا بازنویسی کند.

وراثت چندسطحی در پایتون چیست؟

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

وراثت سلسله مراتبی در پایتون چیست؟

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

آیا می توانیم از وراثت چندگانه در پایتون استفاده کنیم؟

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

جمع‌بندی

درک انواع وراثت در پایتون، برای توسعه‌دهندگانی که قصد طراحی اپلیکیشن‌های پیچیده دارند، اهمیت حیاتی دارد. از مهمترین مزایای وراثت می‌توان به موارد زیر اشاره کرد.

  • تکرار کدها را کاهش می‌دهد.
  • خوانایی کدها را بهبود می‌بخشد.
  • سرعت توسعه را به‌طور بهینه‌ای افزایش می‌دهد.

وراثت‌های یگانه، چندگانه و چندسطحی، وقتی در حال طراحی «پایگاه کد» (Codebase) آن‌ها هستید، هرکدام مزیت‌ها و معایب متمایزی را ارائه می‌دهند. پس توسعه‌دهندگان باید همه گزینه‌ها را همزمان با اجرای کد درنظر داشته باشند.

زمانی که از وراثت در پایتون استفاده می‌کنید، ضروری است که قاعده DRY (خودت را تکرار نکن) را درنظر داشته باشید و از افراط در ایجاد ساختارهای سلسله مراتب پیچیده کلاسی باید دوری کنید. با تسلط به انواع وراثت در پایتون، توسعه‌دهندگان با مهارت می‌توانند کدهای کارآمدتر و با مدیریت بهتر ایجاد کنند که تولید نرم‌افزارها و برنامه‌های برتر را نتیجه دهد. در این مطلب از فرادرس سعی کردیم تا دید جامع و کاملی از وراثت در پایتون بدهیم و کمک کنیم تا در آینده برنامه‌نویس‌های توانمندی به جامعه برنامه‌نویسی ایران اضافه شوند.