شی گرایی در عالم پایتون  (بخش دوم)

in Python searchخب بخش مهمی که باید بیشتر توجه داشت همین بخش هست پس توصیه ایمنی را جدی گرفته مراقبه خودتون باشید به این بخش خوب گوش جان بسپاریداین جایی است که ما از کلاس برای تعریف برنامه استفاده می‌کنیم به طوری که هر شی از همان نوع کلاس دارای ویژگی‌های یک‌سان باشد.پایتون وظایف ویژه‌ای را برای کلاس ها ، که به وسیله پسوند ها و پیشوند ها که با علامت "_" هستند، فراهم می‌کندپایتون یک تابع مخصوص به نام __init__ را ارایه می‌دهد که هر زمان که ما یک نمونه از یک کلاس بسازیم و این تابع برای ایجاد طرح کلی شی استفاده می‌شود و ابتدای نمونه سازی از کلاس اجرا خواهد شد درست مانند تابع constructor یا construct به ترتیب در زبان های php , jsتابع __init__ هر زمان که یک شی ایجاد می‌شود فراخوانی می‌شود. تابع به یک پارامتر اجباری نیاز دارد که با کلمه "self" فراخوانی میشود. در اینجا "self" به خود شی ساخته شده از روی کلاس اشاره میکنهمثال 1-1class PostalAddress: def __init__(self): passدر داخل این تابع __init__ ، ما متغیرهای نمونه محلی را ایجاد می کنیم که حالت (ویژگی های قابل شناسایی) شیء ساخته شده از این کلاس را تعریف می کنند. مانند خط 3 و 4مثال 2-11 class PostalAddress: 2 def __init__(self): 3 self.name = &quotABC&quot 4 self.street = &quotCentral Street - 1&quot 5 cP1 = PostalAddress() 6 print(cP1.__dict__) # {'street': 'Central Street - 1', 'name': 'ABC'}عبارت "self" یک کلمه کلیدی در پایتون نیست، این یک عرف در برنامه نویسی پایتون است که از واژه"self" به عنوان یک مرجع برای دسترسی به شی ساخته شده از کلاس استفاده می‌کنیم، با این حال، ما می‌توانیم آن را هر چیزی که می‌خواهیم، برای مثال، نامگذاری کنیم. مثال 3-1class PostalAddress: def __init__(theClassInstance): theClassInstance.name = &quotABC&quot theClassInstance.street = &quotCenteral Street - 1&quotولی روش بهتر برای استفاده همان عبارت "self" که دیگر برنامه نویسان منظور شما متوجه خواهند شدتوابع در کلاس، جنبه رفتاری آن شی را فراهم می‌کنند. اجازه دهید فقط یک تابع برای چاپ حالت فعلی شی ایجاد کنم. تابع را prnInfo می‌نامندمثال 4-11class PostalAddress: 2 def __init__(self): 3 self.name = &quotABC&quot 4 self.street = &quotCenteral Street - 1&quot 5 def prnInfo(self): 6 print(&quotName => &quot, self.name, &quot Street =>&quot, self.street) 7 cP1 = PostalAddress() 8 cP1.prnInfo() #Name => ABC Street => Centeral Street - 1دقیقاً مانند عملکرد __init__ ، تمام توابع خود را به عنوان یک پارامتر اجباری می گیرند. با این حال ، هنگامی که ما این تابع را فراخوانی می کنیم یعنی تابع "prnInfo" در خط 8 ، هیچ پارامتری را به آن منتقل نمی کنیم زیرا پایتون نمونه شی را به صورت خودکار می گیرد. به عبارتی به خط های 3 و 4 اشاره میکنیمما همچنین می توانیم به جای یک شیء ، توابع را با استفاده از کلاس فراخوانی کنیم ، اما اگر بخواهیم متد را از طریق کلاس فراخوانی کنیم با این حال، اگر می‌خواهیم متد را از طریق کلاس ، فراخوانی کنیم. باید شی ساخته شده از کلاس را به تابع "prnInfo" معرفی کنیم ، پایتون نمی‌داند که کدام یک به عنوان "self" عمل می‌کند.فراخوانی با استفاده از کلاس به شکل زیر است: خط های 1 و 3مثال 5-11 cP1 = PostalAddress()# Calling the function using class, we provide the instance 2 PostalAddress.prnInfo(cP1)# This is same as 3 cP1.prnInfo() تا اینجای کار کلاس PostalAddress شبیه همان شی های استاتیک بود، زیرا ما نام و خیابان را در داخل تابع "__init__" مقدار دهی کردیم. با این حال، ما می‌خواهیم اشیا نمونه دیگری با مقادیر مختلف بسازیم.این مقادیر را به عنوان پارامترهای ورودی در تابع init در نظر بگیرید که در کد زیر نشان‌داده شده‌است:مثال 6-1# PostalAddress taking name and street as input parameter class PostalAddress: def __init__(self, name, street): self.name = name self.street = street def prnInfo(self): print(&quotName => &quot, self.name, &quot Street =>&quot, self.street) cP1 = PostalAddress(&quotABC&quot, &quotCentral Street - 1&quot) cP1.prnInfo() cP2 = PostalAddress(&quotDEF&quot, &quotCentral Street - 2&quot) cP2.prnInfo()خب ما میتونیم به پارامتر های تابع __init__ مقادیر پیش فرض بدهیم که بعدا در هنگام فراخوانی درصورت فراموشی مقدار دهی به شی ، ان مقدار پیش فرض جایگزین شود که از بروز خطا جلوگیری کند در خط 2مثال 7-11 class PostalAddress: 2 def __init__(self, name = &quotDefault Name&quot, street = &quotCentral Street - 1&quot): 3 self.name = name 4 self.street = street 5 cP0 = PostalAddress(); # 0 arguments 6 cP1 = PostalAddress(&quotABC&quot) # 1 argument 7 cP2 = PostalAddress(&quotDEF&quot, &quotCentral Street - 2&quot) # 2 argumentsایجاد نمونه متغیرها در توابع چندگانهاین معنی نیست که ما فقط می‌توانیم متغیرهای مورد نظر را فقط درون تابع__init__ ایجاد کنیم. ما می‌توانیم همین کار را در هر یک از اعضای کلاس انجام دهیم.تنها مشکل این است که آن متغیرها تنها زمانی ایجاد خواهند شد که تابع ایجاد متغیر نمونه فراخوانی می‌شود. اشاره به خط 5 و 6 و فراخوانی در خط 9مثال 8-11 class PostalAddress: 2 def __init__(self, name = &quotDefault Name&quot, street = &quotCentral Street - 1&quot): 3 self.name = name 4 self.street = street 5 def createMember(self): 6 self.newMember = &quotTemporary Value&quot 7 cP0 = PostalAddress(); 8 print(cP0.__dict__); # prints {'name': 'Default Name', 'street': 'Central Street - 1'} 9 cP0.createMember(); 10 print(cP0.__dict__); # print {'name': 'Default Name', 'street': 'Central Street - 1', 'newMember': 'Temporary Value'}متغیرهای کلاساغلب اوقات، آدرس‌های افراد در یک جامعه کوچک، برخی از اطلاعات مشترک برای مثال کد پستی را به اشتراک می‌گذارند.این به این معنی است که تمام اشیا کلاس PostalAddress باید کد پستی یکسانی داشته باشندیك راه برای دستیابی به این هدف نوشتن كد پستی در متد __init__ به گونه ای است كه در هر شیء ایجاد شده از این کلاس در دسترس باشد.مثال 9-1class PostalAddress: def __init__(self, name = &quotDefault Name&quot, street = &quotCentral Street - 1&quot): self.name = name self.street = street self.postalcode = 12345 # Hardcoding Postal Code cP0 = PostalAddress(); print(cP0.__dict__); # prints {'postalcode': 12345, 'name': 'Default Name', 'street': 'Central Street - 1'} cP1 = PostalAddress(&quotABC&quot) print(cP1.__dict__); # prints {'postalcode': 12345, 'name': 'ABC', 'street': 'Central Street - 1'}با این حال، اگر بخواهیم بعد کد پستی را تغییر دهیم، این یک مشکل است. تنها راه برای انجام این کار، تغییر دستی برای هر شی است،مثال 10-1cP0.postalcode = 54321 cP1.postalcode = 54321 ... ... cPn.postalcode = 54321این کار نه تنها خسته کننده نیست بلکه راه را برای بروز اشتباهات هموار میکند پس راه کار چیست؟خوشبختانه، ما می‌توانیم متغیرهای کلاس داشته باشیم که در این موارد میتوانند به روز شوندclass variable یک متغیر است که نه در داخل متدهای موجود کلاس تعریف نمیشود بلکه در سطح بدنه کلاس تعریف می شود این متغیر در کلیه نمونه های PostalAddress در دسترس است بیایید ببینیم چگونه می توانیم متغیرهای کلاس را تعریف کنیممثال 1-2class PostalAddress: postalCode = 12345; # class Variable def __init__(self, name = &quotDefault Name&quot, street = &quotCentral Street - 1&quot): self.name = name self.street = street cP0 = PostalAddress() print(cP0.postalCode) # print 12345قبل از اینکه به راه‌هایی برای تغییر متغیر کلاس نگاهی بیندازیم به گونه‌ای که هر نمونه از کلاس با postalCode جدید به روز می‌شود، ما نیاز به درک یک تفاوت عمده بین متغیرهای کلاس و متغیرهای نمونه داریم. class variable به عنوان بخشی از کلاس تعریف می شوند و به عنوان نمونه نیستنداگر ما دستور "__cP0.__dict" را اجرا کنیم "کد پستی" را در آنجا پیدا نمی کنیم. مثال 2-2print(cP0.__dict__) # prints {'street': 'Central Street - 1', 'name': 'Default Name'}برای یافتن "کد پستی" ، باید از خود کلاس متغیرش را فراخوانی کنیم نه از شی ساخته شده از کلاسمثال 3-2print(PostalAddress.__dict__) # prints {'postalCode': 12345. .... } amongst many other thingsاین توالی جستجوی پایتون است که ابتدا به "نمونه" نگاه می‌کند، و اگر تابع / عملکرد پیدا نشود، به "کلاس" نگاه می‌کند. به همین دلیل است که ما می‌توانیم cP۰.postalCode را با استفاده از شی نمونه چاپ کنیم.روش کلاسمتغیرهای کلاس را می توان به دو روش یا با استفاده از خود کلاس یا با استفاده از تابع کلاس تغییر داد. برای تغییر استفاده از خود کلاس، باید کد زیر را بنویسیممثال 4-2PostalAddress.postalCode = 54321با این کار "کد پستی" نه تنها برای موارد موجود ، بلکه برای تمام مواردی که پس از اجرای این خط ایجاد می شود ، تغییر خواهد کرد.مثال 5-2# Instance created BeforecP0 = PostalAddress() cP1 = PostalAddress() PostalAddress.postalCode = 54321 # Instance created after changecP2 = PostalAddress() print(cP0.postalCode) # prints 54321 print(cP1.postalCode) # prints 54321 print(cP2.postalCode) # prints 54321راه دیگر برای دستیابی به نتیجه مثال بالا class method ها در پایتون است متد ()classmethod یک روش‌ کلاس را برای عملکرد مشخص داده است. شما میتوانید برای شی های ساخته شده از کلاس به مقدار class variable دسترسی داشته و آنرا تغییر دهید. cls در خط 7 خیلی شبیه به "self" عمل میکند. در حالی که روش کلاس تعیین‌کننده است، ما باید به وضوح به زبان پایتون بگوییم که این روش یک روش کلاسی است که از کلمه کلیدی استفاده می‌کند.classmethod@ یعنی در خط 6مثال 6-21 class PostalAddress: 2 postalCode = 12345; # class Variable 3 def __init__(self, name = &quotDefault Name&quot, street = &quotCentral Street - 1&quot): 4 self.name = name 5 self.street = street 6 @classmethod 7 def newPostalCode(cls, newcode): 8 cls.postalCode = newcodeخب در" Instance methods" کلمه ,"self" را به عنوان پارامتر اجباری می گیرند ، در حالی کهClass methods کلمه "class" را به عنوان پارامتر اجباری می گیرند.در هر دو مورد ، لازم نیست که ما صراحتا از Instance or Class عبور کنیم ، پایتون به طور خودکار از آن مراقبت می کند.اکنون می توانیم این روش جدید newPostalCode را از طریق Instance یا از طریق Class فراخوانی کنیم. در هر دو مورد ، نتیجه نهایی یکسان خواهد بود. در اینجا نحوه استفاده ما از روش Instance استفاده میکنیممثال 7-2cP0 = PostalAddress() cP1 = PostalAddress()# Call using Instance PostalAddress.newPostalCode(9999) cP2 = PostalAddress() print(cP0.postalCode) # prints 9999 print(cP1.postalCode) # prints 9999 print(cP2.postalCode) # prints 9999به پایان آمد این دفتر حکایت همچنان باقی است :)