پایتون زبانی شی گرا است که از تمامی ویژگی ها و قابلیت های زبان های شی گرا پشتیبانی می کند. در پایتون هر زمان که متغیری ایجاد می شود، متغیر نمونه یا شی از یک کلاس است. به طور مثال با ایجاد متغیر نوع رشته، این متغیر نمونه ای (یا شی) از کلاس str خواهد بود. همین طور اگر متغیری از نوع لیست یا دیکشنری یا تاپل ایجاد کنیم، این متغیرها نمونه ای از کلاس های list و dict و تاپل خواهند بود.

یک کلاس را می توان گروهی از داده ها (متغیرها یا خصیصه ها) و توابع (متد یا Method) در نظر گرفت که این داده ها و توابع را اعضای (Members) یک کلاس می نامند. در مفاهیم شی گرایی، منظور از داده های عضو کلاس، متغیرهایی هستند که اطلاعات ورودی به کلاس را در خود ذخیره می کنند. به متغیرهای درون کلاس، خصیصه یا خصوصیت های (Property) کلاس نیز می گویند.

توابع درون کلاس را متدهای (Methods) کلاس نیز می نامند که فتار (Behavior) کلاس را تعیین می کنند. داده های ورودی درون متغیرهای کلاس ذخیره می شوند و سپس بر اساس ساختار و برنامه نویسی انجام شده برای کلاس، توسط متدهای کلاس مورد استفاد قرار می گیرند. هر تابع یا متد کلاس می تواند یک خروجی تولید کند.

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

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

در مفاهیم شی گرایی به نمونه ای از کلاس، شی (Object) می گویند، که در واقع این شی یک متغیر نمونه (Instance Variable) از کلاس مربوطه است. همانطور که گفته شد، در پایتون تمامی متغیرهایی که از انواع رایج و استاندارد پایتون (عدد صحیح و ممیز شناور، رشته ، لیست ا، دیکشنری و تاپل) ایجاد می شوند، نمونه ای از یک کلاس هستند. به طور پیشفرض با انتساب یک نوع به یک متغیر، آن متیغر از نوع همان مقدار انتساب داده شده است ولی می توان به صورت های زیر نیز متغیرها را ایجاد کرد.

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

استفاده از عبارت pass در تعریف کلاس

کلاس های SampleClass1 و SampleClass2 دارای یک عبارت pass هستند.  pass عملگر Null است و وقتی اجرا می شود، هیچ چیزی اتفاق نمی افتد. در واقع زمانی که بخواهیم کلاس را با نامش معرفی و بعد دستورها و بدنه آنرا تعریف کنیم، از عبارت pass استفاده می کنیم. قطعه کد ۴ مثال ساده ای از تعریف یک کلاس را نشان می دهد.

دو شی sample1 و sample2 به ترتیب نمونه هایی از کلاس های SampleClass1 و SampleClass2 هستند. در خطوط ۱۱ و ۱۴ می خواهیم محتوای اشیا را چاپ کنیم ولی چون منطق و دستورهای بدنه کلاس هنوز تعریف نشده اند، بنابراین دو شی بی محتوا هستند و خروجی print به صورت زیر هستند که نشان می دهد آنها به ترتیب نمونه هایی (Instance) از کلاس های SampleClass1 و SampleClass2 هستند.

<__main__.SampleClass1 instance at 0x7f402d72e320>

<__main__.SampleClass2 instance at 0x7f402d72e170>

پس از ایجاد شی (یا نمونه ای) از کلاس می توان از طریق نام شی و به صورت object.class_member به اعضای درون کلاس دسترسی داشت. به طور مثال قطعه کد ۵ باز نویسی شده قطعه کد ۴ است و هر کلاس دارای یک عبارت print است.

پس از اجرای کدهای بالا خروجی مشابه زیر نشان داده خواهد شد. چون کدها و منطق هر دو کلاس فقط از یک print ساده تشکیل شده است، بنابراین در ابتدا و به ترتیب print sample1 و print sample2 پیغام های درون هر کلاس نشان داده می شود و مجدد اطلاعات مربوط به هر شی نشان داده می شوند.

Object from SampleClass1

Object from SampleClass2

<__main__.SampleClass1 instance at 0x7f631cf63248>

<__main__.SampleClass2 instance at 0x7f631cf635f0>

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

self و کاربرد آن در شی گرایی در پایتون

متدها یا توابع عضو هر کلاس دارای یک پارامتر به نام self هستند که در ابتدای لیست پارامترها قرار می گیرند. به عبارتی هر تابع عضو کلاس حتما دارای یک پارامتر به نام self است که پیش از هر پارامتر دیگری باید نوشته شود. این پارامتر اجباری است ولی هیچ مقدار ورودی را دریافت نمی کند. قطعه کد ۶ بازنویسی شده قطعه کد ۵ است. هر دو کلاس دارای متد show_message هستند.

وظیفه متدهای show_message در هر دو کلاس فقط چاپ و نمایش یک خروجی است و هیچ آرگومان ورودی را دریافت نمی کنند. اما پارامتر self در زمان نوشتن تابع اجباری است و حتما باید به عنوان اولین پارامتر نوشته شود. قطعه کد ۷ دو روش را برای ایجاد یک شی از هر کلاس و دسترسی به تابع show_message به عنوان عضو کلاس ها را نشان می دهد.

 متغیر self در پایتون معادل با اشاره گر this در زبان  ++C و مرجع (یا reference) در زبان های #C و جاوا است. بنابراین برای اشاره و دسترسی به اعضای درون کلاس (متغیرها و توابع) باید از self برای اشاره و دسترسی به آنها استفاده کنیم.

مثال ۱ – یک کلاس برای جمع و تفریق دو عدد بنویسید. کلاس دارای یک متد به نام set است که دو پارامتر ورودی (دو عدد) دریافت می کند و آنها را در متغیر ها (عضوهای کلاس) ذخیره می کند. دو متد نیز جمع و تفریق را انجام می دهند.

 تابع set_number دو پارامتر number1 و number2 را به عنوان ورودی دریافت می کند و آنها را درون متعیرهای عضو کلاس یعنی number1 و number2 ذخیره می کند. در اینجا نام پارامترهای ورودی تابع (یعنی number1 و number2) با متغیرهای عضو کلاس (یعنی self.number1 و self.number2) هم نام هستند. ولی دو پارامتر ورودی تنها در خود این تابع قابل دسترسی و معتبر هستند. برای همین منظور مقدار آنها را درون دو متغیر عضو کلاس (یعنی self.number1 و self.number2) ذخیره می کنیم تا این مقادیر ورودی درون کلاس و توسط دیگر اعضا قابل دسترسی باشند.

در متدهای summation و subtraction نیز از طریق self به متغیرهای عضو کلاس، یعنی number1 و number2 دسترسی خواهیم داشت. بنابراین کاربر باید یک شی از کلاس ایجاد کند و سپس توسط این شی تابع set_number را با دو آرگومان ورودی فراخوانی کند. سپس این مقادیر ورودی در متغیرهای عضو کلاس ذخیره می شوند و درون هر متد عضو کلاس از طریق self به این متغیرها دسترسی پیدا می کنیم. در قطعه کدهای ۹ و  ۱۰ دو شی obj1 و obj2 را ایجاد شده اند. در قطعه کد ۹ متد summation و در قطعه کد ۱۰ متد subtraction فراخوانی شده اند. هر شی با مقادیر متفاوت مقدار دهی و در نهایت توسط print مقادیر هر شی برای عضو های number1 و number2 چاپ شده اند.

فرض کنید در زمان ایجاد شی (یا نمونه ای) از کلاس Math به جای ارسال دو آرگومان، فقط یک آرگومان به متد (تابع) set_numbers ارسال شود. در این صورت خطای زیر نشان داده می شود.

Traceback (most recent call last):

File “/home/amirnami/c.py”, line 31, in <module>

obj1.set_numbers(10)

TypeError: set_numbers() takes exactly 3 arguments (2 given)

مطابق خطا باید سه آرگومان به تابع ارسال شود. دلیل آن این است که تابع دو آرگومان number1 و number2 و همچنین self را دریافت می کند. self باید اولین پارامتر در تعریف تابع باشد. اما چه چیزی به self ارسال می شود؟ self  هیچ ورودی را دریافت نمی کند بلکه نام خود شی به آن ارسال می شود. بنابراین شکل ارسال آرگومان ها به طور مثال به صورت زیر خواهد بود. همانطور که در قطعه کد ۱۱ می بینید نام شی به self ارسال شده است.

 مثال ۲ – کلاسی به نام Employees بنویسید که نام، نام خانوادگی، آدرس ایمیل و شهر محل سکونت زندگی کارمند را دریافت کند و در غالب یک دیکشنری این اطلاعات را ذخیره کند. این کلاس از طریق متد set_emp اطلاعات اولیه را دریافت می کند و از طریق تابع get_emp اطلاعات کارمند را نشان می دهد. همچنین ورود آدرس ایمیل و محل سکونت اجباری نیستند.

 به دلیل آنکه email و location اختیاری هستند، مقدار پیشفرض None گرفته اند. در خط ۴ متغیر user از نوع دیکشنری که عضو کلاس است ایجاد تعریف شده است. سپس مقادیر ورودی توسط آرگومان های متد set_emp در غالب key = value ها ذخیره می شوند. متد get_emp نیز محتوای متغیر user برای شی ایجاد شده را بر می گرداند.