|
31 | 31 |
|
32 | 32 | در مبحث شی گرایی به پنهانسازی اطلاعات درونی یک شی و محدود کردن دسترسی به آنها از بیرون، **کپسولهسازی (Encapsulation)** گفته میشود - در واقع Encapsulation برابر است با **Information hiding**. |
33 | 33 |
|
34 | | -زبان برنامهنویسی پایتون از فلسفهای به نام «اینجا همه بزرگسال هستیم» "we are all consenting adults here" پیروی میکند! بنابراین این زبان برخلاف زبانهایی همانند Java یک Encapsulation قوی و محافظت شده در اختیار برنامهنویس قرار نمیدهد. پایتون به برنامهنویس اعتماد دارد و میگوید «اگر دوست داری در مکانهای تاریک پرسه بزنی، من مطمئنم که دلیل خوبی داری و هیچ مشکلی ایجاد نمیکنی!» |
| 34 | +زبان برنامهنویسی پایتون از فلسفهای به نام «اینجا همه بزرگسال هستیم» "we are all consenting adults here" پیروی میکند! بنابراین این زبان برخلاف زبانهایی مانند Java و ++C یک Encapsulation قوی (strong) در اختیار برنامهنویس قرار نمیدهد. پایتون به برنامهنویس اعتماد دارد و میگوید «اگر دوست داری در مکانهای تاریک پرسه بزنی، من مطمئنم که دلیل خوبی داری و هیچ مشکلی ایجاد نمیکنی!» |
| 35 | + |
| 36 | + |
| 37 | +.. tip:: |
| 38 | + به صورت پیشفرض تمام اجزای داخلی یک کلاس، **public** هستند و از هر جایی خارج از کلاس مرتبط خود، قابل دستیابی میباشند. |
| 39 | + |
| 40 | +.. tip:: |
| 41 | + بر اساس یک قرارداد مابین برنامهنویسان پایتون، چنانچه ابتدای نام Attributeها و Methodها با **یک کاراکتر خط زیرین** (``_``) آغاز شود، این مفهوم را با خود میرساند که «دست نزنید مگر داخل همان کلاس یا subclassهای آن». رعایت این قرارداد معادل سطح دسترسی **protected** در Java و ++C میباشد. |
| 42 | + |
| 43 | +.. tip:: |
| 44 | + |
| 45 | + زبان برنامهنویسی پایتون از تکنیک «دستکاری نام» یا **name mangling** [`ویکیپدیا <https://en.wikipedia.org/wiki/Name_mangling>`__] پشتیبانی میکند. به کمک این تکنیک و با قراردادن **دو کاراکتر خط زیرین** (``__``) در ابتدای نام هر یک از اجزای داخلی یک کلاس، میتوان معادل سطح دسترسی **private** در Java و ++C را پیادهسازی کرد [`اسناد پایتون <https://docs.python.org/3/tutorial/classes.html#private-variables>`__]. |
| 46 | + |
| 47 | +به نمونه کد زیر توجه نمایید: |
| 48 | + |
| 49 | +.. code-block:: python |
| 50 | + :linenos: |
| 51 | +
|
| 52 | + class Student: |
| 53 | +
|
| 54 | + def __init__(self, name, score=0): |
| 55 | + self.name = name |
| 56 | + self.__score = score |
| 57 | + |
| 58 | + def display(self): |
| 59 | + print('name:', self.name) |
| 60 | + print('score:', self.__score) |
| 61 | +
|
| 62 | +
|
| 63 | + student = Student('Saeid', 70) |
| 64 | +
|
| 65 | + #accessing using method |
| 66 | + student.display() |
| 67 | +
|
| 68 | + #accessing directly from outside |
| 69 | + print('-' * 10, 'Accessing directly from outside') |
| 70 | + print('name:', student.name) |
| 71 | + print('score:', student.__score) |
| 72 | +
|
| 73 | +
|
| 74 | +:: |
| 75 | + |
| 76 | + name: Saeid |
| 77 | + score: 70 |
| 78 | + ---------- Accessing directly from outside |
| 79 | + name: Saeid |
| 80 | + Traceback (most recent call last): |
| 81 | + File "sample.py", line 20, in <module> |
| 82 | + print('score:', student.__score) |
| 83 | + AttributeError: 'Student' object has no attribute '__score' |
| 84 | + |
| 85 | +دادههای private را در خارج از کلاس نمیتوان مستقیم مورد دستیابی قرار داد و همانطور که از نمونه کد بالا مشاهده میشود دستیابی چنین عناصری در پایتون باعث بروز AttributeError میشود. اما گفته شد که پایتون Encapsulation قوی ندارد، چه اتفاقی افتاد؟ |
| 86 | + |
| 87 | +مفسر پایتون بر اساس تکنیک **name mangling**، نام تمام عناصری که تنها با **دو کاراکتر خط زیرین** شروع شده باشند (مانند ``spam__``) را به صورت زیر با افزودن نام کلاس به ابتدای آن تغییر میدهد:: |
| 88 | + |
| 89 | + _classname__spam |
| 90 | + |
| 91 | +بنابراین اگر برنامهنویسی به دنبال دستیابی نام موجود (``spam__``) در کلاس باشد، چیزی پیدا نخواهد کرد. با این کار پایتون به صورت ضعیف امکان دور نگهداشتن برخی از عناصر را از حالت عمومی فراهم آورده است. برای مثال پیش داریم:: |
| 92 | + |
| 93 | + >>> dir(student) |
| 94 | + ['_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'] |
| 95 | + |
| 96 | + |
| 97 | +متدهای Setter و Getter |
| 98 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 99 | + |
| 100 | +در برنامهنویسی شی گرا چنانچه بخواهیم دسترسی به دادهای را به شدت محدود کنیم، به آن داده سطح دسترسی private را اعمال میکنیم. اما گاهی میخواهیم تنها روند دستیابی و تغییر برخی از دادهها را کنترل کنیم - دسترسی مجاز است ولی چگونگی آن مهم است - در این صورت علاوه بر تنظیم سطح دسترسی private به آن عناصر متدهایی را برای تغییر (به عنوان Setter) و دستیابی (به عنوان Getter) آنها نیز میبایست ایجاد کنیم: |
| 101 | + |
| 102 | +.. code-block:: python |
| 103 | + :linenos: |
| 104 | +
|
| 105 | + class Student: |
| 106 | +
|
| 107 | + def __init__(self, name, score=0): |
| 108 | + self.name = name |
| 109 | + self.__score = score |
| 110 | +
|
| 111 | + def set_score(self, score): |
| 112 | + if isinstance(score, int) and 0 <= score <= 100: |
| 113 | + self.__score = score |
| 114 | +
|
| 115 | + def get_score(self): |
| 116 | + return self.__score |
| 117 | +
|
| 118 | +
|
| 119 | + student = Student('Saeid', 70) |
| 120 | + student.set_score(99) |
| 121 | + student.set_score('100') |
| 122 | + student.set_score(-10) |
| 123 | + print(f'{student.name}, score:', student.get_score()) |
| 124 | +
|
| 125 | +
|
| 126 | +:: |
| 127 | + |
| 128 | + Saeid, score: 99 |
| 129 | + |
35 | 130 |
|
36 | 131 |
|
37 | 132 |
|
|
0 commit comments