در نوشته شی گرایی و تعریف کلاس در پایتون – بخش یکم پیش زمینه ای درباره شی گرایی در پایتون گفتیم و در دنباله آن، در این نوشته می خواهیم دیگر مفاهیم شی گرایی مانند متدهای پیش فرض __init__ یا همان تابع سازنده (Construct Function) و متد __new__ و دیگر مفاهیم شی گرایی مانند ارث بری را آموزش دهیم.

تابع (متد) و __init__ در کلاس ها

در پایتون تعدادی متد وجود دارند که در برنامه نویسی شی گرا معنا و کاربرد خاصی دارند. اگر متد __init__ در کلاس تعریف شده باشد، این متد بلافاصله پس از ایجاد یک نمونه (Instance) یا شی از کلاس، فراخوانی می شود. از این متد برای مقدار دهی کردن خودکار شی های کلاس، در زمان تعریف شی، استفاده می شود.

با توجه به مثال ۲ و قطعه کد ۱۲، از تابع set_emp برای مقدار دهی متغیرهای درون کلاس و به طبع مقدار دهی کردن شی کلاس، استفاده کرده ایم. ولی می توانیم با استفاده از متد __init__ و تعریف پارامترهای ورودی، مقدار دهی شی ایجاد شده از کلاس را به صورت خودکار و بدون نیاز به متد دیگری (در اینجا set_emp) انجام دهیم. بنابراین با توجه به مثال ۲، قطعه کد ۱۳ بازنویسی شده قطعه کد ۱۲ است.

در قطعه کد ۱۶ و ۱۹ دو شی ایجاد شده اند. بر خلاف قطعه کد ۱۲، در اینجا در زمان ایجاد اشیا، مقادیر آرگومان ها توسط نام کلاس ارسال شده اند. این مقداردهی توسط تابع (متد) __init__ انجام می شود.

تابع (متد) __new__ در کلاس ها

__init__ تابعی است که برای مقداردهی کردن مقادیر لازم برای کلاس استفاده می شوند. مقدار دهی  توسط تابع __init__ بلافاصله  پس از ایجاد شی انجام می شود. اما خود شی چگونه ایجاد می شود؟ در پایتون تابع (متد) __new__ یک شی از کلاس مورد نظر را ایجاد می کند. اگر تابع __init__ را درون کلاس تعریف کرده باشید، پیش از آنکه این تابع فراخوانی و مقدار دهی را انجام دهد، تابع __new__ به صورت خودکار فراخوانی می شود و یک نمونه از کلاس را ایجاد می کند و برگشت می دهد. بنابراین به صورت خلاصه می توان گفت که :

  • تابع __new__ به صورت مخفی و دور از دید برنامه نویس اجرا می شود و یک شی از کلاس را برگشت می دهد.
  • استفاده از تابع __init__ اختیاری است و از آن برای مقدار دهی کردن خودکار شی در زمان ایجاد شی استفاده می شود.
  • تابع __init__ پس از تابع __new__ اجرا می شود.

__init__ معمولا اولین تابعی است که درون کلاس تعریف می شود ولی هیچ اجباری برای تعریف و استفاده از این تابع وجود ندارد.

مثال ۳ – کلاسی به نام Book تعریف کنید که اطلاعات کتاب ها را نگه می دارد. تابع __init__ این کلاس نام و نام خانوادگی نویسنده، عنوان، محل (مکان) انتشار، نام انتشارات و سال انتشار کتاب را دریافت می کند. همچنین کلاس دارای تابع book_info است که اطلاعات کتاب را نشان می دهد.

پیدا کردن متغیرها و متدهای مرتبط با یک شی

 همانطور که در قطعه کد ۲ گفته شد در پایتون هر متغیری که ایجاد می کنیم به صورت یک شی است و این بدین معنی است که یک کلاس وجود دارد که شی (متغیر) از آن ایجاد شده است و در واقع نمونه ای از آن کلاس است. مطابق قطعه کد ۱۵ یک متغیر از نوع رشته ایجاد کرد ایم، پس این متغیر شی یا نمونه ای از کلاس str است. کلاس str نوع رشته (str) و متدهای مربوط به آنرا پیدا سازی می کند.

در پایتون دستور (تابعی) به نام ()dir وجود دارد که نام یک شی را به عنوان ورودی دریافت می کند و سپس فهرست تمامی متغیرها و متدهایی که به این شی مربوط است را نشان می دهد. در واقع توسط ()dir فهرست تمامی متغیرها و متدهای (اعضای) کلاسی که شی از آن ایجاد شده است را می توانیم مشاهده کنیم.

همانطور که از خروجی قطعه کد ۱۵ مشخص است، متغیر یا شی string چون مقدار رشته دریافت کرده است، بنابراین یک شی (یا نمونه ای) از کلاس str است و به همین خاطر متدهای کلاس str توسط این متغیر قابل دسترسی هستند. شکل ۱ نشان می دهد که متغیر string به عنوان شی یا نمونه ای از کلاس str به متدهای کلاس دسترسی دارد.

تابع ()isinstance

از تابع ()isinstance برای پیدا کردن اینکه آیا یک شی نمونه ای از کلاس است یا نه استفاده می شود. این تابع دو آرگومان وروی دریافت می کند. آرگومان اول نام یک شی (نمونه) از کلاس یا نام یک متغیر است. آرگومان دوم نام یک کلاس یا یک تاپل از نام کلاس ها است. اگر شی یا متغیر نمونه ای از کلاس (یا کلاس های درون تاپل) باشد، مقدار True و در غیر این صورت مقدار False برگشت داده می شود.

ارث بری یک کلاس از کلاس دیگر

 ارث برای (Inheritance) اجازه می دهد تا ویژگی ها و قابلیت های یک کلاس را در کلاس دیگر استفاده کنیم که در اصطلاح گفته می شود یک کلاس از کلاس دیگر مشتق (Derived) شده است. به کلاسی که از کلاس دیگر متشق شده کلاس فرزند (Child Class) یا کلاس مشتق شده (Derived Class) و به کلاسی که کلاس دیگری از آن متشق شده است کلاس والد (Parent Class) یا کلاس پایه (Base Class) گفته می شود.

 همانطور که گفته شد کلاس ها شامل تعدادی متغیر و تابع (متد) هستند که با ارث بری یک کلاس از کلاس دیگر، کلاس فرزند متغیر ها و متدهای کلاس والد را به ارث می برد. قاعدتا بدنه تعریف هر دو کلاس متفاوت از یکدیگر است و هر یک اجزای خودش را دارد ولی ویژگی های مشترکی میان این دو کلاس هستند که با ارث بری، کلاس فرزند ویژگی های مشترک را از کلاس والد به ارث می برد. فرمت کلی ارث بری یک کلاس از کلاس دیگر به صورت قطعه کد ۱۶ است. در زمان تعریف کلاس مشتق شده (DerivedClass) نام کلاس والد یا کلاس پایه (BaseClass) در میان پرانتزهای باز و بسته قرار می گیرد.

مثال ۴ – کلاسی به نام User تعریف کنید که در آن یک متغیر به نام username و یک متد به نام printUserName دارد که نام کاربری را چاپ می کند. متد setJobName شغل کاربر را دریافت می کند و همچنین کلاس از طریق تابع __init__ مقدار متغیر username را دریافت می کند.

برای ایجاد نمونه یا شی از کلاس User باید به صورت زیر انجام شود.

مطابق قطعه کد ۱۹ کلاس دیگری تعریف می کنیم که از کلاس User مشتق شده است. که همانند قطعه کد ۱۷ از طریق تابع __init__ نام کاربری را دریافت می کند و تابع دیگری به نام setSkils در آن وجود دارد که محارت ها و زبان های برنامه نویسی مورد علاقه کاربر را دریافت می کند. چون این کلاس از کلاس User مشتق شده توابع setJobName و printUserName را از آن به ارث برده است.

برای ایجاد نمونه یا شی از کلاس User باید به صورت زیر انجام شود.

Override کردن متدهای کلاس والد در کلاس فریند

Method Overriding قابلیتی است که در آن یک کلاس فرزند می تواند پیاده سازی خاص خود را از متدهای کلاس پدر داشته باشد و در زمان اجرا آن پیاده سازی بجای پیاده سازی پدر استفاده شود. در قطعه کدها ۱۷ تابع (متد) setJobName تعریف شده است که چون کلاس Programmer در قطعه کد ۱۹ از کلاس User ارث بری کرده است، نمونه کلاس Programmer به متد setJobName دسترسی خواهد داشت. از طریق Method Overriding می تواینم در یک کلاس فرزند متد کلاس والد را با همان نام پیاده سازی کنیم به طوری که عملکرد و بدنه تابع Override شده متاوت از بدنه آن در کلاس والد باشد. در قطعه کد ۲۱ کلاس Programmer باز نویسی شده است.