GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||
GeezerVison is showing pythonpersian.com — درس ۲۰: شی گرایی (OOP) در پایتون: Encapsulation و چندریختی (Polymorphism) — کتاب پایتون به پارسی
"نه مرگ آنقدر ترسناک است و نه زندگی آنقدر شیرین که انسان برای این دو شرفش را بدهد" نامتان جاوید باد درس ۲۰: شی گرایی (OOP) در پایتون: Encapsulation و چندریختی (Polymorphism)¶
Photo by sanjiv nayak¶ این درس در ادامه دروس گذشته مرتبط با آموزش شی گرایی در زبان برنامهنویسی پایتون میباشد. تاکنون با دو تا از چهار مفهوم مهم در شیگرایی آشنا شدهایم: وراثت (Inheritance) - درس هجدهم و انتزاع (Abstraction) - درس نوزدهم. این درس به بررسی دو مورد باقیمانده، یعنی کپسولهسازی (Encapsulation) و چندریختی (Polymorphism) در زبان برنامهنویسی پایتون میپردازد. ✔ سطح: متوسط کپسولهسازی (Encapsulation)¶در مبحث شی گرایی به پنهانسازی اطلاعات درونی یک شی و محدود کردن دسترسی به آنها از بیرون، کپسولهسازی (Encapsulation) گفته میشود - در واقع Encapsulation برابر است با Information hiding. پیش از هر چیزی لازم است بدانیم که زبان برنامهنویسی پایتون از فلسفهای پیروی میکند که در جمله «اینجا همه بزرگسال هستیم» "we are all consenting adults here" خلاصه میشود! بنابراین این زبان برخلاف زبانهایی مانند Java و ++C یک Encapsulation قوی (strong) در اختیار برنامهنویس قرار نمیدهد. پایتون به برنامهنویس اعتماد دارد و میگوید «اگر دوست داری در مکانهای تاریک پرسه بزنی، من مطمئنم که دلیل خوبی داری و هیچ مشکلی ایجاد نمیکنی!» نکته به صورت پیشفرض تمام اجزای داخلی یک کلاس، public هستند و از هر جایی خارج از کلاس مرتبط خود، قابل دستیابی میباشند. نکته بر اساس یک قرارداد مابین برنامهنویسان پایتون، چنانچه ابتدای نام Attributeها و Methodها با یک کاراکتر خط زیرین ( نکته زبان برنامهنویسی پایتون از تکنیک «دستکاری نام» یا name mangling [ویکیپدیا] پشتیبانی میکند. به کمک این تکنیک و با قراردادن دو کاراکتر خط زیرین ( به نمونه کد زیر توجه نمایید: 1class Student: 2 3 def __init__(self, name, score=0): 4 self.name = name 5 self.__score = score 6 7 def display(self): 8 print('name:', self.name) 9 print('score:', self.__score) 10 11 12student = Student('Saeid', 70) 13 14#accessing using method 15student.display() 16 17#accessing directly from outside 18print('-' * 10, 'Accessing directly from outside') 19print('name:', student.name) 20print('score:', student.__score) name: Saeid score: 70 ---------- Accessing directly from outside name: Saeid Traceback (most recent call last): File "sample.py", line 20, in <module> print('score:', student.__score) AttributeError: 'Student' object has no attribute '__score' دادههای private را در خارج از کلاس نمیتوان مستقیم مورد دستیابی قرار داد و همانطور که از نمونه کد بالا مشاهده میشود دستیابی چنین عناصری در پایتون باعث بروز AttributeError میشود. اما گفته شد که پایتون Encapsulation قوی ندارد، چه اتفاقی افتاد؟ مفسر پایتون بر اساس تکنیک name mangling، نام تمام عناصری (Attributeها و Methodها) که تنها با دو کاراکتر خط زیرین شروع شده باشند (مانند _classname__spam
بنابراین اگر برنامهنویسی به دنبال دستیابی نام موجود ( >>> dir(student) ['_Student__score', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'display', 'name'] متدهای Setter و Getter¶در برنامهنویسی شی گرا چنانچه بخواهیم دسترسی به دادهای را به شدت محدود کنیم، به آن داده سطح دسترسی private را اعمال میکنیم. اما گاهی میخواهیم تنها روند دستیابی و تغییر برخی از دادهها را کنترل کنیم - دسترسی مجاز است ولی چگونگی آن مهم است - در این صورت علاوه بر تنظیم سطح دسترسی private به آن عناصر متدهایی را برای تغییر (به عنوان Setter) و دستیابی (به عنوان Getter) آنها نیز میبایست ایجاد کنیم: 1class Student: 2 3 def __init__(self, name, score=0): 4 self.name = name 5 self.__score = score 6 7 def set_score(self, score): 8 if isinstance(score, int) and 0 <= score <= 100: 9 self.__score = score 10 11 def get_score(self): 12 return self.__score 13 14 15student = Student('Saeid', 70) 16student.set_score(99) 17student.set_score('100') 18student.set_score(-10) 19print(f'{student.name}, score:', student.get_score()) Saeid, score: 99 چندریختی (Polymorphism)¶چندریختی از کلمات یونانی Poly (زیاد) و Morphism (ریخت) گرفته شده است و در برنامهنویسی شی گرا به این معنی است که از یک نام یکسان متد برای انواع مختلف میتوان استفاده کرد. در مبحث برنامهنویسی شی گرا به شیوههای زیر میتوان چندریختی (Polymorphism) را پیادهسازی کرد:
در ادامه به بررسی و پیادهسازی هر مورد در زبان برنامهنویسی پایتون خواهیم پرداخت. Method Overriding¶این نوع از چندریختی در هنگام پیادهسازی وراثت (Inheritance - درس هجدهم) قابل استفاده است و تا کنون نیز بارها از آن بهره گرفتیم!. در واقع به پیادهسازی دوباره یک متد از کلاس superclass در کلاس subclass را Method Overriding میگویند. در این مواقع متد superclass در زیر سایه متد هم نام در subclass قرار میگیرد و هنگام فراخوانی متد توسط اشیای کلاس subclass، این متد subclass است که فراخوانی میگردد: 1class Animal: 2 3 def breathe(self): 4 print('Animal, breathing...') 5 6 def walk(self): 7 print('Animal, walking...') 8 9 10class Dog(Animal): 11 12 def walk(self): 13 print('Dog, walking...') 14 15 16dog = Dog() 17dog.breathe() 18dog.walk() Animal, breathing... Dog, walking... در این نمونه کد، کلاس Dog از کلاس Animal ارثبری دارد و متد نکته همانطور که پیشتر نیز انجام میدادیم، چنانچه تمایل به فراخوانی متد متناظر در superclass را داشته باشیم، میتوانیم از تابع نکته اتفاقی که در بحث انتزاع (Abstraction) و ارثبری از کلاسهای Abstract شاهد بودیم نیز در واقع پیروی از همین مبحث بوده و با این تفاوت که Method Overriding اجباری میبود. نکته در زبان برنامهنویسی پایتون تنها این نام متدهاست که در Method Overriding نقش دارد و تعداد پارامترهای تعریف شده در هر متد مهم نمیباشد. بنابراین متد همنام موجود در subclass میتواند پارامترهای متفاوتی نسبت superclass داشته باشد. البته تغییر در پارامترهای متد بازپیادهسازی شده چیزی نیست که بخواهیم آن را پیشنهاد بدهیم (به خصوص در بحث پیادهسازی متدهای Abstract) چرا که یکی از پیامدهای آن شکسته شدن اصل Liskov Substitution Principle [ویکیپدیا] میشود. Method Overloading¶این نوع از چندریختی به امکان کنارهم قرار گرفتن چندین متد همنام ولی با پارامترهای متفاوت (از نظر تعداد یا نوع) در کنار هم میباشد. یک شی میتواند با ارسال آرگومانهای متفاوت و فراخوانی یک نام یکسان از متد، کارهای متفاوتی را به انجام برساند. همانطور که در قسمت پیش نیز اشاره شد، در زبان برنامهنویسی پایتون تعداد و نوع پارامترهای تعریف شده برای یک تابع یا متد، هیچ ارتباطی با هویت آن متد ندارد و یک متد تنها با نام آن شناسایی میشود. بنابراین Method Overloading در پایتون پشتیبانی نمیشود و چنانچه چندین متد یا تابع همنام با پارامترهای متفاوت در یک کلاس یا ماژول در کنار هم باشند، خطایی رخ نمیدهد ولی باید توجه داشته باشید که متد یا تابع آخر، تمام موارد پیش از خود را در زیر سایه خواهد گرفت: 1class Animal: 2 3 def breathe(self): 4 print('breathing...') 5 6 def walk(self): 7 print('walking...') 8 9 def walk(self, time=30): 10 print(f'{time} minutes, walking...') 11 12 def walk(self, minutes=30, seconds=59): 13 print(f'{minutes} minutes and {seconds} seconds, walking...') 14 15 16animal = Animal() 17animal.walk() 30 minutes and 59 seconds, walking... همانطور که از خروجی نمونه کد بالا مشاهده میشود، با فراخوانی متد Operator Overloading¶گونهای از مفهوم چندریختی که در زبان برنامهنویسی پایتون پشتیبانی میشود، Operator Overloading میباشد که به انجام عملیات متفاوت با استفاده یک عملگر (Operator - درس ششم) یکسان اشاره دارد. برای مثال عملگر >>> a = 3 >>> b = 'string' >>> a + a 6 >>> b + b 'stringstring' زیان برنامهنویسی پایتون این قابلیت را در اختیار برنامهنویس قرار میدهد که بتواند عملیات مورد نظر خود را برای اشیای خود در هنگام مواجه با عملگرها فراهم آورد. این کار با استفاده از پیادهسازی برخی متدهای خاص ممکن میشود و در ادامه به معرفی متدهای معادل چند عملگر پایتون میپردازیم. توجه داشته باشید که تعداد این متدهای بسیار بیشتر از اینها بوده و در ازای تمام عملگرهای ممکن، یک متد نظیر قابل پیادهسازی میباشد، برای مطالعه بیشتر میتوانید به مستندات پایتون مراجعه نمایید:
به عنوان نمونه یک کلاس Number جدید میسازیم و عملگر 1class Number: 2 3 def __init__(self, number): 4 self.number = number 5 6 # adding two objects 7 def __add__(self, other_number): 8 return self.number + other_number.number 9 10 11a = Number(5) 12b = Number(7) 13 14result = a + b 15 16print(f'{a.number } + {b.number } =', result) 5 + 7 = 12 به عنوان مثالی دیگر، شخصیسازی سنجش برابر بودن دو شی: 1class Student: 2 3 def __init__(self, name, score=0): 4 self.name = name 5 self.score = score 6 7 def __eq__(self, other_student): 8 return self.score == other_student.score 9 10 11a = Student('Saeid', 75) 12b = Student('Babak', 75) 13 14print(a == b) True
😊 امیدوارم مفید بوده باشه | ||||||||||||||||||||||||||||||
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |