در آموزش گذشته با نحوۀ تعریف کلاس و همچنین چگونگی نمونهسازی از روی آن آشنا شدیم اما در این آموزش قصد داریم ببینیم پس از تعریف یک کلاس در پایتون چه اتفاقاتی در پشت پرده میافتند.
در واقع، پس از تعریف هر کلاس دلخواهی در زبان برنامهنویسی پایتون، یکسری اتریبیوت پیشفرض به آن کلاس افزوده میشوند به طوری که هر یک کارکرد مختص به خود را دارا است که در این آموزش برخی از پرکاربردترین این دست اتریبیوتها را معرفی خواهیم کرد. برای شروع این مبحث، کدی مانند زیر را مد نظر قرار میدهیم:
class Student:
'Common base class for all students'
count = 0
def __init__(self, name, family):
self.name = name
self.family = family
Student.count += 1
def displayCount(self):
print("Total Student:", Student.count)
def displayStudent(self):
print("Name:", self.name, ", family:", self.family)
اسکریپت این برنامه را در فایلی به نام StudentClass.py ذخیره کرده و آن را اجرا میکنیم. در کد فوق ابتدا با بهکارگیری کیورد class کلاسی به نام Student تعریف کرده و در ادامه علامت : را قرار داده سپس با رعایت تورفتگی وارد بدنۀ داخلی کلاس شده و استرینگی در قالب یک کامنت مابین علائم تککوتیشن به صورت ' ' قرار دادهایم (در آموزش آشنایی با مستندسازی در پایتون به تفصیل بدین موضوع پرداختهایم.)
حال در ادامه متغیری به نام count تعریف کرده و مقدار اولیۀ ۰ را به آن دادهایم که به عنوان یکی از اتربیوتهای کلاس Student به شمار میرود و قرار است تا تعداد آبجکتهای ساختهشده از روی آن را نگهداری کند. سپس متد از پیش تعریفشدۀ ()__init__ را نوشتهایم که نقش کانستراکتور را بازی میکند و دارای سه پارامتر ورودی است. پارامتر اول تحت عنوان self به منظور ارجاع دادن به آبجکتهای ساختهشده از روی کلاس جاری مورد استفاده قرار میگیرد و پارامتر دوم تحت عنوان name برای نگهداری اتریبیوت مرتبط با نام و در نهایت پارامتر family را داریم که به منظور نگهداری اتریبیوت نام خانوادگی آبجکت مد نظر تعریف شدهاند.
داخل کانستراکتور کلاس نیز گفتهایم در صورت ساخت آبجکتی از روی کلاس Student مقدار معادل آرگومان ورودیِ name و family به ترتیب به اتریبیوتهای name و family منتسب گردد و در ادامه دستور Student.count += 1 را داریم که بدین ترتیب گفتهایم در صورت ساخت آبجکتی از روی کلاس، مقدار اتریبیوت count یک واحد افزایش یابد (همانطور که در آموزش آشنایی با کیورد گلوبال گفتیم، متغیر count در داخل متد ()__init__ و در یک دستور انتسابی به کار رفته است و از همین روی یک متغیر لوکال ارزیابی میشود.)
در واقع، به منظور دسترسی به اتریبیوت count هم در داخل کلاس و هم خارج از آن به صورت گلوبال ابتدا نام کلاس را ذکر کرده سپس علامت . را قرار دادهایم چرا که بدون ذکر نام کلاس نمیتوانیم خارج از کلاس Student به آن دسترسی داشته باشیم. در چنین شرایطی، با ساخت آبجکت از روی کلاس Student متد ()__init__ فراخوانی شده و مقادیر معادل هر یک از آرگومانهای ورودی را به ترتیب به متغیرهای name و color منتسب میکند و در نهایت دستور count += 1 اجرا میشود که معادل count = count + 1 است.
همانطور که پیشتر گفتیم، count یک متغیر لوکال ارزیابی میشود و از همین روی مفسر پایتون در داخل متد ()__init__ به دنبال آن میگردد اما با این حال متغیری با شناسۀ count در داخل این متد تعریف و مقداردهی اولیه نشده است که بدین ترتیب با ذکر نام کلاس در ابتدای آن میتوانیم به صورت گلوبال به آن دسترسی داشته و از همین روی در هر بار ساخت آبجکت از روی کلاس Student مقدار اتربیوت count یک واحد افزایش پیدا میکند.
در ادامه، متدی تحت عنوان ()displayCount با پارامتر ورودی self تعریف کردهایم که به منظور اشاره به آبجکت ساختهشده از روی کلاس جاری مورد استفاده قرار میگیرد. فانکشن مذکور را برای نمایش تعداد آبجکتهای ساختهشده از روی کلاس Student تعریف کردهایم که در آن گفتهایم در صورت فراخوانی، مقدار منتسب به اتریبیوت count را به همراه استرینگ «:Total Student» در خروجی چاپ کند.
به همین ترتیب فانکشن دیگری به نام ()displayStudent تعریف کردهایم که در صورت فراخوانی روی آبجکت ساختهشده از روی این کلاس، نام و نام خانوادگی دانشآموز را در قالب استرینگی متشکل از مقادیر منتسب به هر یک از اتریبیوتهای name و family از آبجکت مربوطه در خروجی چاپ میکند.
حال پس از تعریف کلاس Student قصد داریم با بهکارگیری فانکشن ()print ببینیم هر یک اتریبیوتهای از پیش تعریفشده در این کلاس چه مقادیری را نگهداری میکنند. اولین اتریبیوت تحت عنوان __doc__ شناخته میشود و نشاندهندۀ داکیومنت مربوط به کلاس مد نظر میباشد که در مورد کلاس Student استرینگ مربوط به کامنت درجشده در سطر دوم از بدنۀ کلاس را در خروجی ریترن میکند. برای این منظور کد زیر را در نظر میگیریم:
>>> print(Student.__doc__)
Common base class for all students
در کد فوق به منظور دسترسی به اتریبیوت مد نظر از کلاس Student ابتدا نام کلاس را آورده و در ادامه یک علامت . قرار دادهایم سپس نام اتریبیوت از پیش تعریفشدۀ __doc__ را ذکر کردهایم و آن را به عنوان پارامتر ورودی به فانکشن ()print دادهایم که از همین روی استرینگ «Common base class for all students» در خروجی چاپ میشود.
اتریبوت از پیش تعریفشدۀ دیگری به نام __name__ داریم که دربرگیرندۀ نام کلاس مربوطه است و به منظور تست آن روی کلاس Student ساختاری مانند بلوک زیر را مد نظر میدهیم:
>>> print(Student.__name__)
Student
در کد فوق اتربیوت __name__ از کلاس Student را به عنوان آرگومان ورودی به فانکشن ()print دادهایم که با اجرای آن نام کلاس مربوطه در خروجی چاپ میشود.
در حین اجرای کلاس فوق، اتریبیوت از پیش تعریفشدۀ دیگری تحت عنوان __module__ به این کلاس افزوده میشود که نشاندهندۀ نام ماژولی است که کلاس مد نظر در آن تعریف شده است به طوری که سازوکار این اتریبیوت برای کلاس Student به صورت زیر خواهد بود:
>>> print(Student.__module__)
__main__
خروجی حاصل از اجرای کد فوق بیانگر این موضوع است که کد مد نظر در ماژول خاصی تعریف نشده و از طریق محیط اسکریپتی یا تعاملی پایتون و در یک حالت استاندارد اجرا شده است.
تعریف کلاس در نسخۀ سوم زبان برنامه نویسی پایتون به دو روش انجام میشود که در ادامه فرم کلی هر یک را تشریح میکنیم. روش اول که در آموزش آشنایی با مفهوم Class با آن آشنا شدیم، یک حالت مرسوم به منظور تعریف کلاس بوده و فرم کلی آن بدین صورت میباشد:
class Sample:
#blocks of code
اما روش دوم بدین ترتیب است که در جلوی نام کلاس علائم () قرار داده و داخل آن آرگومانی تحت عنوان object داریم که فرم کلی آن بدین صورت میباشد:
class Sample(object):
#blocks of code
به طور کلی، هر دو روش فوقالذکر به منزلۀ تعریف کلاسی دلخواه تحت عنوان Sample بوده و بدین صورت تفسیر میشوند كه هنگام تعریف کلاس در زبان برنامهنویسی پایتون، تمامی کلاسها به صورت پیشفرض از یک کلاس به اصطلاح Base یا والد تحت عنوان object ارثبری میکنند (در آموزشهای آتی با مفهوم Inheritance و چگونگی ارثبری کلاسها از یکدیگر بیشتر آشنا خواهیم شد.)
اتریبیوت __bases__ نیز آبجکتی از جنس تاپل است و کلاسهای والدی را نشان میدهد که کلاس مد نظر از آنها ارثبری کرده است و هر یک از آنها را با علامت , از یکدیگر جدا میکند. در مورد کلاس Student نیز با اجرای کد زیر خواهیم داشت:
>>> print(Student.__bases__)
(<class 'object'>,)
بنابراین خروجی حاصل از اجرای کد فوق بیانگر این موضوع است که کلاس Student صرفاً از کلاس object ارثبری کرده است و چنانچه کلاس مد نظر از کلاسی دیگر ارثبری کند، به جای استرینگ «object» استرینگ مربوط به نام کلاس والد در خروجی ریترن میشود.
در نهایت، اتریبیوت از پیش تعریفشدۀ __dict__ را داریم که یک آبجکت از نوع دیکشنری بوده و تمامی اتریبیوتهای تعریفشده در کلاس مربوطه را نگهداری میکند. برای مثال در رابطه با کلاس Student داریم:
>>> print(Student.__dict__)
{'__module__': '__main__', '__doc__': 'Common base class for all students', 'count': 1, '__init__': <function Student.__init__ at 0x0000000F65F908C8>, 'displayCount': <function Student.displayCount at 0x0000000F65F90400>, 'displayStudent': <function Student.displayStudent at 0x0000000F65F902F0>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>}
همانطور که میبینید، خروجی حاصل از اجرای کد فوق اتریبیوتهایی با مقادیر متناظرشان را نشان میدهد که به ترتیب شامل ماژول مرتبط با کلاس Student و استرینگ مربوط به کامنت درجشده، اتریبیوت count با تعداد آبجکتهای ساختهشده از روی این کلاس و همچنین سایر اتریبیوتهای آن است.
