From 4db12fdd807f671a2cb93726f86fd62237c8faa5 Mon Sep 17 00:00:00 2001 From: Saeid Date: Sat, 6 Mar 2021 09:36:39 +0330 Subject: [PATCH 01/10] l18: create --- index.rst | 1 + lessons/l18.rst | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 lessons/l18.rst diff --git a/index.rst b/index.rst index 81888b2..b15fdb2 100644 --- a/index.rst +++ b/index.rst @@ -32,6 +32,7 @@ lessons/l15 lessons/l16 lessons/l17 + lessons/l18 log donate-report python-interactive diff --git a/lessons/l18.rst b/lessons/l18.rst new file mode 100644 index 0000000..b7d1504 --- /dev/null +++ b/lessons/l18.rst @@ -0,0 +1,49 @@ +.. role:: emoji-size + +.. meta:: + :description: کتاب آموزش زبان برنامه نویسی پایتون به فارسی، آموزش شی گرایی در پایتون، معرفی رابطه های وراثت (Inheritance) و انجمن (Association) در پایان، OOP در پایتون + :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, تابع, کتابخانه, پایتون, شی گرایی در پایتون + + +درس ۱۸: شی گرایی (OOP) در پایتون: وراثت (Inheritance) و انجمن (Association) +======================================================================================================== + + + +این درس در ادامه درس پیش می‌باشد و به بررسی رابطه بین کلاس‌ها و اشیا می‌پردازد. در درس پنجم مقدمه‌ای از این روابط صحبت شده است و این درس به صورت کامل دو رابطه **HAS-A** یا Inheritance و **IS-A** یا Association در مفهموم شی گرایی و چگونگی پیاده‌سازی آن‌ها در زبان برنامه‌نویسی پایتون را شرح می‌دهد. + + + +:emoji-size:`✔` سطح: متوسط + +---- + + +.. contents:: سرفصل‌ها + :depth: 2 + +---- + + + + + + + + + + + + + + +| + +---- + +:emoji-size:`😊` امیدوارم مفید بوده باشه + +`لطفا دیدگاه و سوال‌های مرتبط با این درس خود را در کدرز مطرح نمایید. `_ + + + From 6fef0fb8f9a0e6c23947e35f536a7d5503cb850f Mon Sep 17 00:00:00 2001 From: Saeid Date: Sat, 6 Mar 2021 09:48:53 +0330 Subject: [PATCH 02/10] l18: start --- lessons/l18.rst | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lessons/l18.rst b/lessons/l18.rst index b7d1504..08d4d43 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -10,7 +10,9 @@ -این درس در ادامه درس پیش می‌باشد و به بررسی رابطه بین کلاس‌ها و اشیا می‌پردازد. در درس پنجم مقدمه‌ای از این روابط صحبت شده است و این درس به صورت کامل دو رابطه **HAS-A** یا Inheritance و **IS-A** یا Association در مفهموم شی گرایی و چگونگی پیاده‌سازی آن‌ها در زبان برنامه‌نویسی پایتون را شرح می‌دهد. +این درس در ادامه درس پیش می‌باشد و به بررسی رابطه بین کلاس‌ها و اشیا می‌پردازد. در درس پنجم مقدمه‌ای از این روابط صحبت شده است و این درس به صورت کامل دو رابطه **IS-A** یا Inheritance و **HAS-A** یا Association در مفهموم شی گرایی و چگونگی پیاده‌سازی آن‌ها در زبان برنامه‌نویسی پایتون را شرح می‌دهد. + +توجه داشته باشید، هم اکنون پشتیبانی نسخه 2x پایتون به پایان رسیده است. بنابراین همانند درس پیش و به منظور جلوگیری از پیچیدگی‌های غیر ضروری، تمام مطالب این درس بر مبنای پایتون 3x ارائه می‌شود. @@ -25,13 +27,28 @@ ---- +وراثت (Inheritance) +---------------------------------- + + + + + + +انجمن (Association) +---------------------------------- + +ترکیب (Composition) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +تجمع (Aggregation) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 47791f10942872a01d4c2a73adf760fa1a31466f Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Sat, 6 Mar 2021 23:19:28 +0330 Subject: [PATCH 03/10] l18: start Inheritance --- _static/l18-python-oop-inheritance.jpg | Bin 0 -> 35278 bytes lessons/l18.rst | 90 +++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 _static/l18-python-oop-inheritance.jpg diff --git a/_static/l18-python-oop-inheritance.jpg b/_static/l18-python-oop-inheritance.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c53adf1cc693ee4acac0fcda88fa05baf63716d GIT binary patch literal 35278 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] قابل مشاهده خواهد بود. با این توضیح صفت ``__self.__class`` حاوی کلاس شی می‌باشد و ``__self.__class__.__name`` نیز نام کلاس شی را در بر دارد - *این موضوع در درس‌های پیش نیز مطرح شده بود*:: + + >>> class Sample: + ... def imethod(self): + ... print(dir(self)) + ... print() + ... print(self.__class__) + ... + >>> + >>> sample = Sample() + >>> sample.imethod() + ['__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__', 'imethod'] + + + >>> + +با این حال، برخی اشیا پایتون حاوی Attributeهایی هستند که ممکن است توسط تابع ``dir`` نمایش داده نشود. از این Attributeها به عنوان Special Attributes یاد می‌شود [`اسناد پایتون `__]. برای مثال صفت ``__definition.__name`` بسته به نوع definition، حاوی نام کلاس، تابع، متد یا غیره می‌باشد. + + +Super Class +~~~~~~~~~~~~ + + + انجمن (Association) ---------------------------------- From 55fc4ccbbc65ed152a9c0ca2331e68e0685016af Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Sun, 7 Mar 2021 22:49:17 +0330 Subject: [PATCH 04/10] l18: at Multiple Inheritance --- lessons/l18.rst | 139 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/lessons/l18.rst b/lessons/l18.rst index 2e68c32..e309f6a 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -109,9 +109,144 @@ با این حال، برخی اشیا پایتون حاوی Attributeهایی هستند که ممکن است توسط تابع ``dir`` نمایش داده نشود. از این Attributeها به عنوان Special Attributes یاد می‌شود [`اسناد پایتون `__]. برای مثال صفت ``__definition.__name`` بسته به نوع definition، حاوی نام کلاس، تابع، متد یا غیره می‌باشد. +همان‌طور که بیان شد subclass‌ها به Attributeهای superclass کلاس خود نیز دسترسی دارند، به نمونه کدی دیگر نیز توجه نمایید: -Super Class -~~~~~~~~~~~~ +.. code-block:: python + :linenos: + + class SuperClass: + super_class_attr = {'one':1, 'two':2} + + def __init__(self, param_1): + self.super_instance_attr = param_1 + + + class SubClass(SuperClass): + sub_class_attr = {'six':6, 'seven':7} + + def __init__(self, param_1, param_2): + super().__init__(param_1) + self.sub_instance_attr = param_2 + + def sub_instance_method(self): + print('Called: sub_instance_method') + print(self.super_instance_attr) + print(self.sub_instance_attr) + + @classmethod + def sub_class_method(cls): + print('Called: sub_class_method') + print(cls.super_class_attr) + print(cls.sub_class_attr) + + + sub = SubClass('param_1', 'param_2') + + print(sub.super_instance_attr) + print(sub.sub_instance_attr) + print('-' * 30) + print(SubClass.super_class_attr) + print(SubClass.sub_class_attr) + print('-' * 30) + sub.sub_instance_method() + print('-' * 30) + SubClass.sub_class_method() + +:: + + param_1 + param_2 + ------------------------------ + {'one': 1, 'two': 2} + {'six': 6, 'seven': 7} + ------------------------------ + Called: sub_instance_method + param_1 + param_2 + ------------------------------ + Called: sub_class_method + {'one': 1, 'two': 2} + {'six': 6, 'seven': 7} + + +.. tip:: + + از درس پیش مفهوم سازنده (Constructor) در شی گرایی را بیاد داریم. چنانچه در superclass متدهای سازنده (``__new__`` و ``__init__``) پیاده‌سازی شده باشند، می‌بایست این متدها در subclass‌ها نیز پیاده‌سازی شوند، نیازی نیست که سرآیند تعریف این دو متد با superclass یکسان باشد ولی می‌بایست مقادیر مورد نیاز متد superclass فراهم شود. برای این کار لازم است داخل متد subclassها به superclass دسترسی داشه باشیم، تابع ``super`` [`اسناد پایتون `__] این امکان را فراهم می‌کند. + +خروجی تابع ``super`` [`اسناد پایتون `__] شی است که نقش واسط را بین دو کلاس subclass و superclass دارد. نمونه کد زیر چگونگی فراخوانی انواع متدهای superclass را از subclass نمایش می‌دهد: + + +.. code-block:: python + :linenos: + + class SuperClass: + + def super_instance_method(self): + print('Called: super_instance_method') + print(self) + + @classmethod + def super_class_method(cls): + print('Called: super_class_method') + print(cls) + + @staticmethod + def super_static_method(): + print('Called: super_static_method') + + + class SubClass(SuperClass): + + def sub_instance_method(self): + super().super_instance_method() + super().super_class_method() + SuperClass.super_static_method() + + @classmethod + def sub_class_method(cls): + super().super_class_method() + SuperClass.super_static_method() + + @staticmethod + def sub_static_method(): + SuperClass.super_static_method() + + + sub = SubClass() + + sub.sub_instance_method() + print('-' * 30) + SubClass.sub_class_method() + print('-' * 30) + SubClass.sub_static_method() + +:: + + Called: super_instance_method + <__main__.SubClass object at 0x7f9c77052898> + Called: super_class_method + + Called: super_static_method + ------------------------------ + Called: super_class_method + + Called: super_static_method + ------------------------------ + Called: super_static_method + +می‌دانیم که مفسر پایتون به صورت خودکار اطلاعات مربوط به شی فراخوانی کننده یک Instance Method را فراهم می‌آورد. زمانی که یک Instance Method از subclass فراخوانی می‌شود، تابع ``super`` می‌تواند آن شی و از طریق آن شی نیز به کلاس دسترسی داشته باشد بنابراین از داخل Instance Method کلاس subclass می‌توان به واسطه تابع ``super`` به هر دو نوع Instance Methodها و Class Methodهای superclass دسترسی پیدا کرد، چرا که تابع ``super`` می‌تواند مقادیر ``self`` و ``cls`` را به منظور فراخوانی متدهای متناظر superclass به دست آورد. + +همچنین می‌دانیم که در فراخوانی Class Method، تنها اطلاعات مربوط به کلاس فراهم است و نه شی. زمانی که یک Class Method از subclass فراخوانی می‌شود، تابع ``super`` می‌تواند به کلاس مرتبط دسترسی داشته باشد بنابراین از داخل Class Method کلاس subclass تنها می‌توان به واسطه تابع ``super`` به Class Methodهای superclass دسترسی پیدا کرد، چرا که تابع ``super`` تنها می‌تواند مقدار ``cls`` را به منظور فراخوانی متدهای متناظر superclass به دست آورد. + +در زمان فراخوانی Static Method نیز می‌دانیم که مفسر پایتون هیچ اطلاعاتی از شی و کلاس مرتبط را فراهم نمی‌آورد، بنابراین فراخوانی این متد با استفاده از تابع ``super`` انجام نمی‌پذیرد. در صورت نیاز به فراخوانی Static Methodهای کلاس superclass در کلاس subclass، همواره می‌توانید از نام کلاس superclass بهره بگیرید. + + +.. note:: + + این برنامه‌نویس است که تصمیم می‌گیرد یک کلاس چگونه طراحی شود. اینکه کدام متد باید از کدام نوع باشد مسئله‌ای است که برنامه‌نویس باید در زمان طراحی کلاس خود به آن فکر کند و از امکانات زبان برنامه‌نویسی پایتون به درستی در جهت بهتر و راحت‌تر به انجام رساندن مسئله خود بهره بگیرد. + +وراثت چندگانه (Multiple Inheritance) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f3cc449d9fc052bc67fe347c35f2eb70d978c5c8 Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Wed, 10 Mar 2021 00:21:50 +0330 Subject: [PATCH 05/10] l18: continue at Multiple Inheritance --- lessons/l18.rst | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/lessons/l18.rst b/lessons/l18.rst index e309f6a..d2f7e2d 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -245,10 +245,183 @@ این برنامه‌نویس است که تصمیم می‌گیرد یک کلاس چگونه طراحی شود. اینکه کدام متد باید از کدام نوع باشد مسئله‌ای است که برنامه‌نویس باید در زمان طراحی کلاس خود به آن فکر کند و از امکانات زبان برنامه‌نویسی پایتون به درستی در جهت بهتر و راحت‌تر به انجام رساندن مسئله خود بهره بگیرد. + +.. tip:: + + هر شی از یک کلاس علاوه بر اینکه از نوع آن کلاس محسوب می‌شود، از نوع superclass نیز به حساب می‌آید. در واقع یک شی نوع subclass، نوع superclass را نیز به ارث می‌برد:: + + >>> class SuperClass: + ... pass + ... + >>> class SubClass(SuperClass): + ... pass + ... + >>> sub = SubClass() + >>> + >>> isinstance(sub, SubClass) + True + >>> isinstance(sub, SuperClass) + True + + وراثت چندگانه (Multiple Inheritance) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +پایتون جزو معدود زبان‌های برنامه‌نویسی مدرنی است که از وراثت چندگانه پشتیبانی می‌کند، چیزی که در زبانی همچون Java نیز وجود ندارد. در واقع پیاده‌سازی وراثت چندگانه چالش‌هایی به همراه دارد، همانند Diamond Problem که در Java ترجیح داده شده است که از وراثت چندگانه پرهیز کند و نبود آن را با پیاده‌سازی مفهومی همچون Interface پوشش دهد [`ویکی‌پدیا `__]. + +فراموش نکنیم در پیاده‌سازی شی گرایی می‌بایست بنابر نیاز برنامه کدهای خود را به کوچک‌ترین واحدهای ممکن تقسیم کنیم و اینکه یک شی بتواند صفات و رفتارهای چندین کلاس را به همراه خود داشته باشد یک نیاز اساسی در شی گرایی است. این الزام فلسفه سادگی پایتون است که مانع از آن می‌شود تا مفاهیمی موازی درکنار هم ایجاد شوند - همانند Class و Interface - وراثت چندگانه راه حل ساده و منطقی زبان برنامه‌نویسی پایتون برای حل این مشکل است و این امکان را می‌دهد که یک کلاس بتواند بیش از یک superclass داشته باشد: +:: + + >>> class SuperClassA: + ... pass + ... + >>> class SuperClassB: + ... pass + ... + >>> class SuperClassC: + ... pass + ... + >>> class SubClass(SuperClassA, SuperClassB, SuperClassC): + ... pass + ... + >>> sub = SubClass() + >>> + >>> isinstance(sub, SubClass) + True + >>> isinstance(sub, SuperClassA) + True + >>> isinstance(sub, SuperClassB) + True + >>> isinstance(sub, SuperClassC) + True + +نمونه کد بالا نمایش ساختار وراثت چندگانه در پایتون است که در آن کلاس SubClass به ترتیب از سه کلاس SuperClassA و SuperClassB و SuperClassC ارث‌بری دارد. + +اکنون مهم‌ترین چالش چگونگی دسترسی به متدهای هر یک از این superclassها می‌باشد. تاکنون برای دسترسی به متدهای superclass از تابع ``super`` استفاده می‌کردیم ولی حالا که صحبت از چندین superclass است، مثلا مقدارهی متد ``__init__`` توسط این تابع چگونه می‌تواند انجام شود؟ چگونه باید به پایتون بگوییم آرگومان‌هایی را که می‌خواهیم دقیقا به متد خاصی از superclass مورد نظر ارسال کند؟ البته نگران نباشید، پایتون مشکلی نخواهد داشت. در ادامه، حالات مختلف حل این مسئله را بررسی خواهیم کرد. +**شیوه یکم:** خیلی ساده، می‌توانیم اصلا از تابع ``super`` استفاده نکنیم و متدهای هر superclass را مستقیم با نام خودش فراخوانی کنیم که البته در این روش لازم است به ازای تمام پارامترهای متد superclass آرگومان متناظر را ارسال نماییم، از جمله برای ``self``: + + +.. code-block:: python + :linenos: + + class SuperClassA: + def __init__(self, param_0, param_3): + print('Called: SuperClassA.__init__()') + self.param_0 = param_0 + self.param_3 = param_3 + + + class SuperClassB: + def __init__(self, param_1): + print('Called: SuperClassB.__init__()') + self.param_1 = param_1 + + class SuperClassC: + def __init__(self, param_2): + print('Called: SuperClassC.__init__()') + self.param_2 = param_2 + + + class SubClass(SuperClassA, SuperClassB, SuperClassC): + def __init__(self, param_0, param_1, param_2, param_3, param_4): + SuperClassA.__init__(self, param_0, param_3) + SuperClassB.__init__(self, param_1) + SuperClassC.__init__(self, param_2) + self.param_4 = param_4 + + + sub = SubClass(0, 1, 2, 3, 4) + + print('param_0: ', sub.param_0) + print('param_1: ', sub.param_1) + print('param_2: ', sub.param_2) + print('param_3: ', sub.param_3) + print('param_4: ', sub.param_4) + +:: + + Called: SuperClassA.__init__() + Called: SuperClassB.__init__() + Called: SuperClassC.__init__() + param_0: 0 + param_1: 1 + param_2: 2 + param_3: 3 + param_4: 4 + + +**شیوه دوم:** فراخوانی تابع ``super`` یک سینتکس معادل نیز دارد که می‌توانیم از آن استفاده کنیم. + + + + +**شیوه سوم:** رفتار تابع ``super`` را عمیق‌تر بشناسیم و درست از آن بهره بگیریم: + + +.. code-block:: python + :linenos: + + class SuperClassA: + def __init__(self, param_0, param_3, *args): + print('Called: SuperClassA.__init__()') + super().__init__(*args) + self.param_0 = param_0 + self.param_3 = param_3 + + + class SuperClassB: + def __init__(self, param_1, *args): + print('Called: SuperClassB.__init__()') + super().__init__(*args) + self.param_1 = param_1 + + class SuperClassC: + def __init__(self, param_2, *args): + print('Called: SuperClassC.__init__()') + super().__init__(*args) + self.param_2 = param_2 + + + class SubClass(SuperClassA, SuperClassB, SuperClassC): + def __init__(self, param_0, param_1, param_2, param_3, param_4): + super().__init__(param_0, param_3, param_1, param_2) + self.param_4 = param_4 + + + sub = SubClass(0, 1, 2, 3, 4) + +.. code-block:: python + :linenos: + + class SuperClassA: + def __init__(self, param_0, param_3, **kargs): + print('Called: SuperClassA.__init__()') + super().__init__(**kargs) + self.param_0 = param_0 + self.param_3 = param_3 + + + class SuperClassB: + def __init__(self, param_1, **kargs): + print('Called: SuperClassB.__init__()') + super().__init__(**kargs) + self.param_1 = param_1 + + class SuperClassC: + def __init__(self, param_2, **kargs): + print('Called: SuperClassC.__init__()') + super().__init__(**kargs) + self.param_2 = param_2 + + + class SubClass(SuperClassA, SuperClassB, SuperClassC): + def __init__(self, p0, p1, p2, p3, p4): + super().__init__(param_0=p0, param_3=p3, param_1=p1, param_2=p2) + self.param_4 = p4 + + + sub = SubClass(0, 1, 2, 3, 4) انجمن (Association) ---------------------------------- From 2ebd471d3ba049195c7ccbaa6e4d322e7a58b265 Mon Sep 17 00:00:00 2001 From: Saeid Date: Wed, 10 Mar 2021 11:29:59 +0330 Subject: [PATCH 06/10] add banner to index --- index.rst | 13 ++++++++++++- lessons/l18.rst | 12 +++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/index.rst b/index.rst index b15fdb2..1912338 100644 --- a/index.rst +++ b/index.rst @@ -9,6 +9,17 @@ کتاب آزاد آموزش پایتون ======================== + +:: + + .-=-. .--. + __ .' '. / " ) + _ .' '. / .-. \ / .-'\ PYTHON TUTORIAL + ( \ / .-. \ / / \ \ / / ^ IN PERSIAN + \ `-` / \ `-' / \ `-` / "BATTERIES INCLUDED", ENJOY! + jgs`-.-` '.____.' `.____.' + + این کتاب تلاشی است برای آموزش زبان برنامه‌نویسی پایتون (Python) بر پایه‌ پیاده‌سازی استاندارد آن (CPython)، به شکلی کامل و ساده که بتواند هر دو شاخه از پایتون (نسخه‌های 3x و 2x) را البته با محوریت نسخه 3x پوشش دهد و همچنین برای افرادی که تاکنون سابقه‌ برنامه‌نویسی نداشته‌اند نیز کاربردی و مفید باشد. یادگیری پایتون نیازی به پیش‌زمینه برنامه‌نویسی ندارد و تنها پیش‌نیاز آن علاقه خوانندگان به فن برنامه‌نویسی است. .. toctree:: @@ -36,7 +47,7 @@ log donate-report python-interactive - + | .. note:: diff --git a/lessons/l18.rst b/lessons/l18.rst index d2f7e2d..c478159 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -351,13 +351,19 @@ param_4: 4 -**شیوه دوم:** فراخوانی تابع ``super`` یک سینتکس معادل نیز دارد که می‌توانیم از آن استفاده کنیم. - -**شیوه سوم:** رفتار تابع ``super`` را عمیق‌تر بشناسیم و درست از آن بهره بگیریم: +**شیوه دوم:** رفتار تابع ``super`` را عمیق‌تر بشناسیم و درست از آن بهره بگیریم: + +لازم است با **Method Resolution Order** یا به اختصار **MRO** در زبان برنامه‌نویسی پایتون آشنا شویم. همانطوری که از نام آن نیز مشخص است، **MRO** ترتیبی که می‌بایست بر اساس آن متدها به ارث برده شوند را مشخص می‌کند. پایتون برای این منظور از الگوریتم C3 linearization بهره گرفته است [`ویکی‌پدیا `__]. هر کلاس پایتون یک Special Attribute به اسم ``__mro__`` دارد که حاوی یک تاپل از ترتیب کلاس‌هایی است که در فرآیند MRO نقش دارند [`اسناد پایتون `__]:: + + + >>> SubClass.__mro__ + (, , , , ) + +می‌دانیم که هر کلاس پایتون به صورت پیش‌فرض از کلاس ``object`` ارث‌بری دارد. از طرفی در فرآیند وراثت چندگانه ترتیب نوشتن superclassها در سرآیند subclass مهم است به این صورت که MRO پایتون برای یافتن متد مورد نظر کلاس‌های superclass را به ترتیب از سمت چپ به راست مورد جستجو قرار می‌دهد. .. code-block:: python :linenos: From 1253b4521a3144ed40f859dcf9640f59d82c2e8e Mon Sep 17 00:00:00 2001 From: Saeid Date: Wed, 10 Mar 2021 15:58:54 +0330 Subject: [PATCH 07/10] * --- lessons/l18.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lessons/l18.rst b/lessons/l18.rst index c478159..f8348d3 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -363,7 +363,13 @@ (, , , , ) -می‌دانیم که هر کلاس پایتون به صورت پیش‌فرض از کلاس ``object`` ارث‌بری دارد. از طرفی در فرآیند وراثت چندگانه ترتیب نوشتن superclassها در سرآیند subclass مهم است به این صورت که MRO پایتون برای یافتن متد مورد نظر کلاس‌های superclass را به ترتیب از سمت چپ به راست مورد جستجو قرار می‌دهد. +می‌دانیم که هر کلاس پایتون به صورت پیش‌فرض از کلاس ``object`` ارث‌بری دارد. از طرفی در فرآیند وراثت چندگانه ترتیب نوشتن superclassها در سرآیند subclass مهم است به این صورت که MRO پایتون برای یافتن متد مورد نظر کلاس‌های superclass را به ترتیب از سمت چپ به راست مورد جستجو قرار می‌دهد (**depth-first left-to-right**)، ابتدا نخستین superclass از سمت چپ انتخاب و برسی می‌گردد، چنانچه آن کلاس نیز superclass داشته باشد، برای آن نیز همین روند طی می‌شود تا به کلاس object برسد، سپس دومین superclass از سمت چپ انتخاب و همین روند تا بالاترین سطح برای آن پیمایش می‌شود و الی آخر:: + + SubClass + --> SuperClassA --> object + --> SuperClassB --> object + --> SuperClassC --> object + .. code-block:: python :linenos: From 7775dd19ce228e71cac19ad9837a1d925f2234dc Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Thu, 11 Mar 2021 23:22:46 +0330 Subject: [PATCH 08/10] l18: beta --- _static/l18-python-mro-diamond.png | Bin 0 -> 2100 bytes _static/l18-python-mro-example.png | Bin 0 -> 27316 bytes lessons/l18.rst | 257 +++++++++++++++++++++++++++-- 3 files changed, 243 insertions(+), 14 deletions(-) create mode 100644 _static/l18-python-mro-diamond.png create mode 100644 _static/l18-python-mro-example.png diff --git a/_static/l18-python-mro-diamond.png b/_static/l18-python-mro-diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddcf00c2df2e6cbc5d3d902dffb8b859968a717 GIT binary patch literal 2100 zcmZ`)do!oh=F3J~0bK?QKBy{8@q(2!h*)NF=JSua}pX4-E~a)9F4wK81ya zuU@@sY-|h;4o*!?m6DPI!S7ryx3aQQAP^7;1UoxBaBDkyy}Pc^&(AL>Cubc56%`fx z`};v~MO|IJw6rubGE!Gp7X+tAMn+%&Fb{$=Gcza@idB^7d6DdW^@@x8rLS|VAo$JB zSnc=BqPefF`q+ypvA3dQ?{|-i^;H0UE8rZOyW@lX;UuFM2(OBBLi zDgC4n()|b;i&7nvkm|+mIoX;aDV3maArob`B1B@2*X$2o-Wxe2G?=MwM0m zE*=E*xE20wMvJj;J5!ZX7{vdWN;pg?5OGzE&*W+*@6%JZa%l1Kh@G|o%khuAb}ah~ zBBGACoo*CAWfWiG?AvRvZFnFbD$`*To8_#1J%X+*y88&47mIMi7`j`+1uL0>0|HTq zu$efh%}5gDqibr5m#;6~NGDax25lf&G7)9hKKXJ2?3FF=K&NGs3o)|Da9Y(vXmiEe zQ4XWM)1%!K7g$s$(_Qi=_pN%nvWXsXDS;{Z64Lj>{q?qLaLEvJ4y4Sr?$4$h;XIRC z1-3=khsv?w@UEJ;RQI}K)9Snt0aktC@IYxs6pc)voPvI$3eDCOytN^4-k!Hn<_Osz zh5!7izp`2W7i4o9(c!;!ISCf1g}6@Jju7ujdZjk=oy|%(<5El2f%E0osxr?xplx=q zwSd}ANB(jx5-oI1+xeQclqZ&jVWO4s%NtHL z;a4Ut9`aIE)_K`AX{GPy)Do=po)d(k&SSb)XNEVecg;WM5hs?PM%uy^n-t9?PzpyC zTPYbyP_AbNyQct1->4}82JhpXvoa8Z9f&HCe>=e>#mV_=3tyvb@oD2D1UEA7(qNgl z{G804Y(1>BdtVcG#qcdE4ccw2lMLk|1W_~+^==}sIshvbWrgAF(zg3G>^( z^D+@JMj>%kk{vF!1g%PT(RM++n142foO^BRJubm1%eH>*-{Vshl>a1T>4c&LIWZIV z9}KaPLQ`E`E_lPU8EE~WLhh%4Zw=OzhYVC-SZ(@rBevg(VkFQk^=!c0rjS=uE>P)y zw9m`@V2bi&jc*z$vs)NZV!M~!9TTD^b!mrH0GYzJ=GcA*E zu(!);{p8hB&2!3Lqj3kGe9`^p;iTlIl$*|4q;vUA7EvdgmysMV+9Xc7BBA2-a7C|n zYd*PcU>+ASLr5FLI98X?lW0<7690qM%sba?6cA%lzrEXPQ!@Ui;C(B0-?JoWOVmx7 z*);e^k_5TtiwE=gK|7`;uhW15&_deI|H6U%6b8ldao_n`&;Ku&pNib`7FxpqN8Njx zkT96&#>e>P5_GMZLs^%QEa6L4eb7}O&>=m$#;25oAqp{uHMR)-?MeBe3CSBe96O=r zQ&_c|q_HDIXOFK#uLcf&wgOXEY|=bu>lQZ=<>gvco}+39Efh&gcL<`ofb-9@Q=w z_?nb-^{=dC=8MovdE_2%})5)oQfEa`LQkkeRV8%{@PZaTU}t4jXc+UryFik{`3obuYk4p(gH5&bV+gz;Pe literal 0 HcmV?d00001 diff --git a/_static/l18-python-mro-example.png b/_static/l18-python-mro-example.png new file mode 100644 index 0000000000000000000000000000000000000000..7048ec756b01e80af31325404afd69952aa125fa GIT binary patch literal 27316 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 literal 0 HcmV?d00001 diff --git a/lessons/l18.rst b/lessons/l18.rst index f8348d3..8db436e 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -5,7 +5,7 @@ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, تابع, کتابخانه, پایتون, شی گرایی در پایتون -درس ۱۸: شی گرایی (OOP) در پایتون: وراثت (Inheritance) و انجمن (Association) +درس ۱۸: شی گرایی (OOP) در پایتون: وراثت (Inheritance) و Association ======================================================================================================== @@ -354,22 +354,17 @@ -**شیوه دوم:** رفتار تابع ``super`` را عمیق‌تر بشناسیم و درست از آن بهره بگیریم: +**شیوه دوم:** رفتار تابع ``super`` را عمیق‌تر بشناسیم و درست از آن بهره بگیریم، برای این منظور می‌بایست شیوه پیمایش superclassها و جستجو برای متد در تابع ``super`` پایتون را بشناسیم، این شیوه با نام **Method Resolution Order** یا به اختصار **MRO** خوانده می‌شود. -لازم است با **Method Resolution Order** یا به اختصار **MRO** در زبان برنامه‌نویسی پایتون آشنا شویم. همانطوری که از نام آن نیز مشخص است، **MRO** ترتیبی که می‌بایست بر اساس آن متدها به ارث برده شوند را مشخص می‌کند. پایتون برای این منظور از الگوریتم C3 linearization بهره گرفته است [`ویکی‌پدیا `__]. هر کلاس پایتون یک Special Attribute به اسم ``__mro__`` دارد که حاوی یک تاپل از ترتیب کلاس‌هایی است که در فرآیند MRO نقش دارند [`اسناد پایتون `__]:: +**Method Resolution Order** ، همانطوری که از نام آن نیز مشخص است، **MRO** ترتیبی که می‌بایست بر اساس آن متدها جستجو شوند را پیدا می‌کند. پایتون برای این منظور از الگوریتم C3 linearization بهره گرفته است [`ویکی‌پدیا `__] (البته از نسخه 2.3 به بعد) [`اسناد پایتون `__]. + +هر کلاس پایتون یک Special Attribute به اسم ``__mro__`` دارد که حاوی یک تاپل از ترتیب کلاس‌هایی است که پایتون بر اساس آن به دنبال یک متد می‌گردد [`اسناد پایتون `__]، در واقع این مقدار حاصل تلاش MRO بر اساس محاسبه الگوریتم C3 linearization برای آن کلاس خواهد بود. برای مثال این مقدار برای کلاس ``SubClass`` ما برابر است با:: >>> SubClass.__mro__ (, , , , ) - -می‌دانیم که هر کلاس پایتون به صورت پیش‌فرض از کلاس ``object`` ارث‌بری دارد. از طرفی در فرآیند وراثت چندگانه ترتیب نوشتن superclassها در سرآیند subclass مهم است به این صورت که MRO پایتون برای یافتن متد مورد نظر کلاس‌های superclass را به ترتیب از سمت چپ به راست مورد جستجو قرار می‌دهد (**depth-first left-to-right**)، ابتدا نخستین superclass از سمت چپ انتخاب و برسی می‌گردد، چنانچه آن کلاس نیز superclass داشته باشد، برای آن نیز همین روند طی می‌شود تا به کلاس object برسد، سپس دومین superclass از سمت چپ انتخاب و همین روند تا بالاترین سطح برای آن پیمایش می‌شود و الی آخر:: - - SubClass - --> SuperClassA --> object - --> SuperClassB --> object - --> SuperClassC --> object - +همانطور که مقدار ``__mro__`` برای کلاس ``SubClass`` مشخص کرده است، پایتون برای جستجوی یک متد ابتدا داخل خود کلاس SubClass را بررسی و سپس شروع به پیمایش superclassهای آن با ترتیب SuperClassA و بعد SuperClassB و بعد SuperClassC می‌کند. آخرین کلاس همواره کلاس object می‌باشد، این کلاسی است که تمام کلاس‌های پایتون به صورت ضمنی و پیش‌فرض از آن ارث‌بری دارند و در یک سلسله مراتب وراثت بالاترین سطح وراثت می‌باشد. اکنون بر اساس این آگاهی می‌توانیم به شیوه زیر عمل کنیم: .. code-block:: python :linenos: @@ -403,6 +398,16 @@ sub = SubClass(0, 1, 2, 3, 4) +همانطور که در نمونه کد بالا مشخص است متد SubClass تنها شامل یکبار فراخوانی تابع ``super`` است و از طرفی هم تمام متدهای متناظر در superclassهای آن نیز شامل فراخوانی تابع ``super`` هستند. + +با آگاهی از حاصل MRO و ترتیب پیمایش superclassها، متد مورد نظر (در اینجا: ``__init__``) را هنگام فراخوانی ``super`` مقداردهی می‌کنیم. یعنی ارسال آرگومان‌ها را به ترتیبی قرار می‌دهیم که ابتدا قرار است متد متناظر در کلاس SuperClassA پیدا، فراخوانی و پارامترهای آن مقداردهی شود، سپس SuperClassB و در نهایت SuperClassC. (سطر ۲۴) + +در این شیوه می‌بایست هر یک از متدهای متناظر در superclassها با متد مورد نظر ما در SubClass، نیز شامل فراخوانی تابع ``super`` باشند. چرا پایتون با اولین نتیجه موفق از یافتن متد، پیمایش را متوقف می‌کند ولی ما می‌خواهیم دیگر متدهای متناظر باقی‌مانده نیز فراخوانی شوند. در نتیجه با فراخوانی مجدد ``super`` این روند را دوباره به اجرا در می‌آوریم. + +متدها در کلاس از قوانین حاکم بر تابع در پایتون پیروی می‌کنند، در نتیجه متدهای متناظر در superclassها باید به گونه‌ای تعریف شده باشند که هر تعداد پارامتر را بپذیرند. برای این منظور در انتهای تعریف پارامترهای این متدها، یک پارامتر ``args*`` قرار داده‌ایم. این پارامتر، تمامی آرگومان‌های اضافی ارسال شده به آن تابع را در خود نگه‌داری می‌کند. در نتیجه برای ادامه روند فراخوانی متدهای نظیر باقی‌مانده، تنها کافی است این مقدار ارسال گردد. (تابع در پایتون - درس دوازدهم) + +اگر شیوه ارسال آرگومان‌ها را به صورت **نام=مقدار** تغییر دهیم، ترتیب ارسال آرگومان‌ها از اهمیت می‌افتد و پیاده‌سازی آسان‌تر و کد خواناتر خواهد بود: + .. code-block:: python :linenos: @@ -429,27 +434,251 @@ class SubClass(SuperClassA, SuperClassB, SuperClassC): def __init__(self, p0, p1, p2, p3, p4): - super().__init__(param_0=p0, param_3=p3, param_1=p1, param_2=p2) + super().__init__(param_0=p0, param_1=p1, param_2=p2, param_3=p3) self.param_4 = p4 sub = SubClass(0, 1, 2, 3, 4) + + +.. note:: + + آنچه در مثال بررسی شد حالتی پیچیده از فراخوانی متد مهم ``__init__`` بود. همواره زمانی که از وراثت چندگانه بهره می‌برید، در زمان فراخوانی یک متد که در دو یا چند superclass مشترک است، می‌بایست به یکی از شیوه‌های ارائه شده عمل نمایید. + + + +Method Resolution Order +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +در این بخش به شرح چگونگی عملکرد **Method Resolution Order** پایتون و محاسبه الگوریتم C3 linearization خواهیم پرداخت. توجه داشته باشید مطالعه این بخش الزامی نیست و در هر زمان شما با استفاده از ``__Class.__mro`` می‌توانید به مقصود دست پیدا کنید! + +برای شروع لازم است قوانین زیر را در نظر داشته باشیم (توجه: در ادامه برای ساده‌سازی توضیحات از ذکر حضور کلاس ``object`` صرف‌نظر شده است!): + +۱) حاصل الگوریتم C3 linearization برای یک کلاس که superclass ندارد برابر با همان کلاس خواهد بود:: + + >>> class A: pass + + >>> A.__mro__ + ( , ) + +۲) چنانچه کلاس مورد نظر تنها شامل یک سطح از سلسله مراتب وراثت می‌باشد، حاصل الگوریتم C3 linearization برای آن کلاس برابر است با لیستی از خود آن کلاس و superclassهای آن کلاس به ترتیبی که قرار گرفته‌اند (از چپ به راست):: + + >>> class A: pass + >>> class B: pass + >>> class C(B, A): pass + + >>> C.__mro__ + (, , , ) + + +۳) محاسبه حاصل الگوریتم C3 linearization برای یک کلاس که بیش از یک سطح سلسله مراتب وراثت دارد کمی زحمت دارد! در حالت کلی این مقدار برابر است با: «لیستی تک عضوی شامل آن کلاس » ``+`` لیستی با اعضای منحصر به فرد که حاصل ادغام (merge) «نتیجه خطی شدن (linearization) superclassهای آن کلاس» و «لیستی از superclassهای آن کلاس». عمل ادغام در اینجا علاوه بر اینکه تکرارپذیر می‌باشد نکاتی دارد که در ادامه ذکر خواهد شد . + +اکنون برای پی بردن به چگونگی ایجاد حاصل ``__Class.__mro`` و درک عملکرد الگوریتم C3 linearization دو مثال معروف در این زمینه را بررسی خواهیم کرد. نخست ساختار الماس (Diamond): + +.. image:: /_static/l18-python-mro-diamond.png + :align: center + +.. code-block:: python + :linenos: + + class A: pass + class B(A): pass + class C(A): pass + class D(B, C): pass + + print (D.__mro__) + +:: + + (, , , , ) + +روند محاسبه الگوریتم C3 linearization برای کلاس ``D`` این مثال به صورت زیر می‌باشد: + +.. code-block:: python + :linenos: + + L(A) := [A] + + L(B) := [B] + merge(L(A), [A]) + = [B] + merge([A], [A]) + = [B, A] + + L(C) := [C] + merge(L(A), [A]) + = [C] + merge([A], [A]) + = [C, A] + + L(D) := [D] + merge(L(B), L(C), [B, C]) + = [D] + merge([B, A], [C, A], [B, C]) + = [D, B] + merge([A], [C, A], [C]) + = [D, B, C] + merge([A], [A], []) + = [D, B, C, A] + + +* سطر ۱: حاصل خطی سازی (linearization) کلاس A یا همان L(A) برابر است با لیستی که تنها شامل همان کلاس A است چرا که کلاس A بدون superclass است. + +* سطر ۳: حاصل خطی سازی (linearization) کلاس B یا همان L(B) برابر است با «لیستی که تنها شامل همان کلاس B» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس B - در اینجا: L(A)» و لیستی از superclassهای کلاس B - در اینجا: [A] + +* سطر۴: حاصل L(A) جایگذاری شده است. + +* سطر ۵: حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با آن کلاس: ``[A] + [B] = [B,A]`` + +* سطر ۷: حاصل خطی سازی (linearization) کلاس C همانند کلاس B می‌باشد. + +* سطر ۱۱: حاصل خطی سازی (linearization) کلاس D یا همان L(D) برابر است با «لیستی که تنها شامل همان کلاس D» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: L(B) , L(C)» و لیستی از superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: [B,C] + +* سطر ۱۲: حاصل L(B) و L(C) جایگذاری شده است. + +* سطر ۱۳: اکنون عملیات ادغام شامل بیش از یک کلاس است، در این شرایط عملیات ادغام و انتخاب یک کلاس مطلوب آنقدر تکرار می‌شود تا دیگر کلاسی باقی نماند. فرآیند انتخاب کلاس مطلوب به این صورت است که از چپ‌ترین کلاس موجود در چپ‌ترین لیست شروع می‌کنیم به انتخاب، این کلاس می‌بایست در باقی لیست‌ها در صورت وجود چپ‌ترین عضو باشد، در غیر این صورت چپ‌ترین کلاس موجود در لیست بعدی انتخاب و بررسی خواهد شد. چنانچه کلاس انتخاب شده شرایط را دارا باشد عمل ادغام برای آن کلاس صورت می‌پذیرد و داخل تمام لیست‌ها در صورت وجود نیز حذف می‌گردد. در اینجا: ابتدا کلاس B انتخاب می‌شود، این کلاس شرایط مطلوب بودن را دارا می‌باشد، در نتیجه عمل ادغام برای آن به انجام می‌رسد. + +* سطر ۱۴: در ادامه عمل ادغام فرآیند خطی سازی برای کلاس D، این بار ابتدا کلاس A انتخاب می‌شود، این کلاس شرایط لازم را ندارد چرا که در جایگاهی از لیست دوم نیز حضور دارد که جایگاه نخست (چپ‌ترین) نیست. کلاس A رها می‌شود و به سراغ لیست دوم می‌رویم، نخستین عضو آن یعنی کلاس C شرایط لازم برای ادغام را دارد، در نتیجه در این مرحله عمل ادغام برای کلاس C به انجام می‌رسد. + +* سطر ۱۵: حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با همان کلاس، در نتیجه کلاس A انتخاب و عمل ادغام برای آن به انجام می‌رسد. + +عملیات با موفقیت به پایان رسید و ما به مقداری برابر با ``__D.__mro`` دست پیدا کردیم! + +| + +اکنون مثال پیچیده‌تری را بررسی می‌کنیم. برگرفته شده از [`اینجا `__] و [`اینجا `__] : + +.. image:: /_static/l18-python-mro-example.png + :align: center + +.. code-block:: python + :linenos: + + class O: pass + + class A(O): pass + class B(O): pass + class C(O): pass + class D(O): pass + class E(O): pass + + class K1(A,B,C): pass + class K2(D,B,E): pass + class K3(D,A): pass + + class Z(K1,K2,K3): pass + + print (Z.__mro__) + +:: + + (, , , , , , , , , , ) + +.. code-block:: python + :linenos: + + L(O) := [O] # the linearization of O is trivially the singleton list [O], because O has no parents + + L(A) := [A] + merge(L(O), [O]) # the linearization of A is A plus the merge of its parents' linearizations with the list of parents... + = [A] + merge([O], [O]) + = [A, O] # ...which simply prepends A to its single parent's linearization + + L(B) := [B, O] # linearizations of B, C, D and E are computed similar to that of A + L(C) := [C, O] + L(D) := [D, O] + L(E) := [E, O] + + L(K1) := [K1] + merge(L(A), L(B), L(C), [A, B, C]) # first, find the linearizations of K1's parents, L(A), L(B), and L(C), and merge them with the parent list [A, B, C] + = [K1] + merge([A, O], [B, O], [C, O], [A, B, C]) # class A is a good candidate for the first merge step, because it only appears as the head of the first and last lists + = [K1, A] + merge([O], [B, O], [C, O], [B, C]) # class O is not a good candidate for the next merge step, because it also appears in the tails of list 2 and 3; but class B is a good candidate + = [K1, A, B] + merge([O], [O], [C, O], [C]) # class C is a good candidate; class O still appears in the tail of list 3 + = [K1, A, B, C] + merge([O], [O], [O]) # finally, class O is a valid candidate, which also exhausts all remaining lists + = [K1, A, B, C, O] + + L(K2) := [K2] + merge(L(D), L(B), L(E), [D, B, E]) + = [K2] + merge([D, O], [B, O], [E, O], [D, B, E]) # select D + = [K2, D] + merge([O], [B, O], [E, O], [B, E]) # fail O, select B + = [K2, D, B] + merge([O], [O], [E, O], [E]) # fail O, select E + = [K2, D, B, E] + merge([O], [O], [O]) # select O + = [K2, D, B, E, O] + + L(K3) := [K3] + merge(L(D), L(A), [D, A]) + = [K3] + merge([D, O], [A, O], [D, A]) # select D + = [K3, D] + merge([O], [A, O], [A]) # fail O, select A + = [K3, D, A] + merge([O], [O]) # select O + = [K3, D, A, O] + + L(Z) := [Z] + merge(L(K1), L(K2), L(K3), [K1, K2, K3]) + = [Z] + merge([K1, A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K1, K2, K3]) # select K1 + = [Z, K1] + merge([A, B, C, O], [K2, D, B, E, O], [K3, D, A, O], [K2, K3]) # fail A, select K2 + = [Z, K1, K2] + merge([A, B, C, O], [D, B, E, O], [K3, D, A, O], [K3]) # fail A, fail D, select K3 + = [Z, K1, K2, K3] + merge([A, B, C, O], [D, B, E, O], [D, A, O]) # fail A, select D + = [Z, K1, K2, K3, D] + merge([A, B, C, O], [B, E, O], [A, O]) # select A + = [Z, K1, K2, K3, D, A] + merge([B, C, O], [B, E, O], [O]) # select B + = [Z, K1, K2, K3, D, A, B] + merge([C, O], [E, O], [O]) # select C + = [Z, K1, K2, K3, D, A, B, C] + merge([O], [E, O], [O]) # fail O, select E + = [Z, K1, K2, K3, D, A, B, C, E] + merge([O], [O], [O]) # select O + = [Z, K1, K2, K3, D, A, B, C, E, O] # done + + + انجمن (Association) ---------------------------------- +وراثت مفهوم پرکاربردی از شی‌گرایی است ولی همانطور که مشاهده خواهید کرد، همیشه تمام روابط را نمی‌توان اینگونه تعریف کرد. با تعریف و چگونگی پیاده‌سازی رابطه **IS-A** در شی گرایی پایتون آشنا شده‌ایم، اکنون می‌بایست با مفهوم رابطه **HAS-A** در شی گرایی آشنا شویم. + +رابطه **HAS-A** زمانی پیش می‌آید که یک شی حاوی یک یا چند شی دیگر باشد. در این رابطه برخلاف آنچه در وراثت (**IS-A**) شاهد آن بودیم، یک شی از طریق یکی شدن با دیگران گسترش پیدا نمی‌کند - بلکه با مالک شدن اشیای دیگر گسترش می‌یابد که در شی گرایی با عنوان **Association** شناخته می‌شود و بر اساس شدت مالکیت، Association بر دو نوع قابل تقسیم است: +* Composition +* Aggregation -ترکیب (Composition) + +توجه داشته باشید که پیاده‌سازی این نوع رابطه (HAS-A) هیچ نکته خاص پایتونی ندارد، تنها تعریف Attribute برای شی است. آنچه مورد تاکید است مفهوم این موارد در برنامه‌نویسی شی گراست که درک آن‌ها خالی از لطف نمی‌باشد. برنامه‌نویس باید بتواند بر اساس مسئله، کلاس‌های خود و روابط بین آن‌ها را به بهترین شکل ممکن طراحی کند، دانستن این موارد به این امر کمک خواهند کرد. + + +Composition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +در **Composition** یک شی بخشی از شی دیگر خواهد بود به صورتی که در حالت تکی مفهومی در برنامه نخواهد داشت و تنها جزیی از شی دیگر بودن است که به آن در برنامه مفهوم می‌بخشد. برای مثال رابطه شی بازو (Arm) و پا (Leg) با شی انسان (Human) از این نوع است. شی Arm تنها در داخل شی Human مفهوم و کاربرد دارد. در واقع شی Arm یا Leg تنها برای استفاده در شی Human ایجاد گردیده‌اند و با از بین رفتن شی Human، شی Arm و Leg نیز از بین می‌روند. + +.. code-block:: python + :linenos: + + class Arm: + pass + + class Leg: + pass + + class Human: + def __init__(self): + self.arm = Arm() + self.leg = Leg() + + human = Human() + +از لحاظ منطقی اگر نگاه کنیم، شی Human برای داشتن قابلیت‌های بازو (Arm) و پا (Leg)، نباید از کلاس‌های مربوط به آن‌ها ارث‌بری داشته باشد. چراکه نمی‌توانیم بگوییم یک Human، یک Arm است (IS-A) ولی می‌توانیم بگوییم که یک Human، یک Arm دارد (HAS-A). + +معمولا در پیاده‌سازی Composition، اشیای مورد نیاز یک شی در داخل آن شی ایجاد می‌گردند. چرا که این اشیا در بیرون از کلاس مورد نظر کاربردی نخواهند داشت و می‌بایست با از بین رفتن شی مالک (در اینجا: Human)، آن‌ها نیز از بین بروند. -تجمع (Aggregation) +Aggregation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +در تعریف **Aggregation** یک شی بخشی از شی دیگر می‌شود ولی به صورت مستقل نیز می‌تواند در برنامه حضور داشته باشد و طول عمر (life cycle) آن‌ها وابسته به یکدیگر نیست. برای مثال رابطه دانش‌آموز (Student) و مدرسه (School) می‌تواند از این نوع در نظر گرفته شود، وقتی School تعطیل می‌شود - Student هنوز وجود دارد. + + +.. code-block:: python + :linenos: + + class Student: + pass + + class School: + def __init__(self, students): + self.students = students + + students = [Student(), Student(), Student()] + + school = School(students) + + +معمولا در پیاده‌سازی Aggregation، اشیای مورد نیاز یک شی در زمان نمونه‌سازی به آن ارسال می‌گردند. چرا که این اشیا در بیرون از کلاس موجودیت‌های مستقلی هستند و طول عمر (life cycle) آن‌ها وابسته به شی مالک (در اینجا: School) نیست. From fe77f6e3e40df89b3b49dff5e6d9ec946f1b19bf Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Fri, 12 Mar 2021 12:41:19 +0330 Subject: [PATCH 09/10] l18: completed --- lessons/l18.rst | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/lessons/l18.rst b/lessons/l18.rst index 8db436e..9674095 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -1,7 +1,7 @@ .. role:: emoji-size .. meta:: - :description: کتاب آموزش زبان برنامه نویسی پایتون به فارسی، آموزش شی گرایی در پایتون، معرفی رابطه های وراثت (Inheritance) و انجمن (Association) در پایان، OOP در پایتون + :description: کتاب آموزش زبان برنامه نویسی پایتون به فارسی، آموزش شی گرایی در پایتون، معرفی رابطه های وراثت (Inheritance) و انجمن (Association) در پایان، OOP در پایتون، ترکیب در پایتون، Method Resolution Order یا MRO پایتون، Composition و Aggregation در پایتون، وراثت چندگانه در پایتون، Multiple Inheritance پایتون :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, تابع, کتابخانه, پایتون, شی گرایی در پایتون @@ -262,6 +262,15 @@ True >>> isinstance(sub, SuperClass) True + >>> isinstance(sub, object) + True + + در واقع این نمایش رابطه **IS-A** می‌باشد. توجه داشته باشید که این رابطه از پایین به بالا می‌باشد و برعکس آن صادق نیست. برای نمونه، مثال نخست را بیاد آورید. گنجشک (Sparrow) یک Animal است ولی Animal لزوما گنجشک نیست! + + تمام کلاس‌های پایتون به صورت ضمنی از کلاس ``object`` ارث‌بری دارند. + + + وراثت چندگانه (Multiple Inheritance) @@ -293,11 +302,13 @@ >>> isinstance(sub, SuperClassB) True >>> isinstance(sub, SuperClassC) + True + >>> isinstance(sub, object) True نمونه کد بالا نمایش ساختار وراثت چندگانه در پایتون است که در آن کلاس SubClass به ترتیب از سه کلاس SuperClassA و SuperClassB و SuperClassC ارث‌بری دارد. -اکنون مهم‌ترین چالش چگونگی دسترسی به متدهای هر یک از این superclassها می‌باشد. تاکنون برای دسترسی به متدهای superclass از تابع ``super`` استفاده می‌کردیم ولی حالا که صحبت از چندین superclass است، مثلا مقدارهی متد ``__init__`` توسط این تابع چگونه می‌تواند انجام شود؟ چگونه باید به پایتون بگوییم آرگومان‌هایی را که می‌خواهیم دقیقا به متد خاصی از superclass مورد نظر ارسال کند؟ البته نگران نباشید، پایتون مشکلی نخواهد داشت. در ادامه، حالات مختلف حل این مسئله را بررسی خواهیم کرد. +اکنون مهم‌ترین چالش چگونگی دسترسی به متدهای هر یک از این superclassها می‌باشد. تاکنون برای دسترسی به متدهای superclass از تابع ``super`` استفاده می‌کردیم ولی حالا که صحبت از چندین superclass است، مثلا مقدارهی متد ``__init__`` (که در تمام superclassها با همین نام وجود دارد) توسط این تابع چگونه می‌تواند انجام شود؟ چگونه باید به پایتون بگوییم آرگومان‌هایی را که می‌خواهیم دقیقا به متد خاصی از superclass مورد نظر ارسال کند؟ البته نگران نباشید، پایتون مشکلی نخواهد داشت. در ادامه، حالات مختلف حل این مسئله را بررسی خواهیم کرد. **شیوه یکم:** خیلی ساده، می‌توانیم اصلا از تابع ``super`` استفاده نکنیم و متدهای هر superclass را مستقیم با نام خودش فراخوانی کنیم که البته در این روش لازم است به ازای تمام پارامترهای متد superclass آرگومان متناظر را ارسال نماییم، از جمله برای ``self``: @@ -406,7 +417,9 @@ متدها در کلاس از قوانین حاکم بر تابع در پایتون پیروی می‌کنند، در نتیجه متدهای متناظر در superclassها باید به گونه‌ای تعریف شده باشند که هر تعداد پارامتر را بپذیرند. برای این منظور در انتهای تعریف پارامترهای این متدها، یک پارامتر ``args*`` قرار داده‌ایم. این پارامتر، تمامی آرگومان‌های اضافی ارسال شده به آن تابع را در خود نگه‌داری می‌کند. در نتیجه برای ادامه روند فراخوانی متدهای نظیر باقی‌مانده، تنها کافی است این مقدار ارسال گردد. (تابع در پایتون - درس دوازدهم) -اگر شیوه ارسال آرگومان‌ها را به صورت **نام=مقدار** تغییر دهیم، ترتیب ارسال آرگومان‌ها از اهمیت می‌افتد و پیاده‌سازی آسان‌تر و کد خواناتر خواهد بود: + + +اگر شیوه ارسال آرگومان‌ها را به صورت **نام=مقدار** تغییر دهیم، ترتیب ارسال آرگومان‌ها از اهمیت می‌افتد و پیاده‌سازی آسان‌تر و کد خواناتر خواهد بود - با این روش چنانچه متدهای مورد نظر در superclasها پارامتر همنام نداشته باشند، حتی ترتیب MRO نیز دیگر اهمیت نخواهد داشت: .. code-block:: python :linenos: @@ -471,7 +484,7 @@ Method Resolution Order (, , , ) -۳) محاسبه حاصل الگوریتم C3 linearization برای یک کلاس که بیش از یک سطح سلسله مراتب وراثت دارد کمی زحمت دارد! در حالت کلی این مقدار برابر است با: «لیستی تک عضوی شامل آن کلاس » ``+`` لیستی با اعضای منحصر به فرد که حاصل ادغام (merge) «نتیجه خطی شدن (linearization) superclassهای آن کلاس» و «لیستی از superclassهای آن کلاس». عمل ادغام در اینجا علاوه بر اینکه تکرارپذیر می‌باشد نکاتی دارد که در ادامه ذکر خواهد شد . +۳) محاسبه حاصل الگوریتم C3 linearization برای یک کلاس که بیش از یک سطح سلسله مراتب وراثت دارد کمی زحمت دارد! در حالت کلی این مقدار برابر است با: «لیستی تک عضوی شامل آن کلاس » ``+`` لیستی با اعضای منحصر به فرد که حاصل ادغام (merge) «نتیجه خطی شدن (linearization) تک تک superclassهای آن کلاس» و «لیستی از superclassهای آن کلاس». عمل ادغام در اینجا علاوه بر اینکه تکرارپذیر می‌باشد نکاتی دارد که در ادامه ذکر خواهد شد . اکنون برای پی بردن به چگونگی ایجاد حاصل ``__Class.__mro`` و درک عملکرد الگوریتم C3 linearization دو مثال معروف در این زمینه را بررسی خواهیم کرد. نخست ساختار الماس (Diamond): @@ -514,25 +527,25 @@ Method Resolution Order = [D, B, C, A] -* سطر ۱: حاصل خطی سازی (linearization) کلاس A یا همان L(A) برابر است با لیستی که تنها شامل همان کلاس A است چرا که کلاس A بدون superclass است. +* **سطر ۱:** حاصل خطی سازی (linearization) کلاس A یا همان L(A) برابر است با لیستی که تنها شامل همان کلاس A است چرا که کلاس A بدون superclass است. -* سطر ۳: حاصل خطی سازی (linearization) کلاس B یا همان L(B) برابر است با «لیستی که تنها شامل همان کلاس B» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس B - در اینجا: L(A)» و لیستی از superclassهای کلاس B - در اینجا: [A] +* **سطر ۳:** حاصل خطی سازی (linearization) کلاس B یا همان L(B) برابر است با «لیستی که تنها شامل همان کلاس B» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس B - در اینجا: L(A)» و لیستی از superclassهای کلاس B - در اینجا: [A] -* سطر۴: حاصل L(A) جایگذاری شده است. +* **سطر ۴:** حاصل L(A) جایگذاری شده است. -* سطر ۵: حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با آن کلاس: ``[A] + [B] = [B,A]`` +* **سطر ۵:** حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با آن کلاس: ``[A] + [B] = [B,A]`` -* سطر ۷: حاصل خطی سازی (linearization) کلاس C همانند کلاس B می‌باشد. +* **سطر ۷:** حاصل خطی سازی (linearization) کلاس C همانند کلاس B می‌باشد. -* سطر ۱۱: حاصل خطی سازی (linearization) کلاس D یا همان L(D) برابر است با «لیستی که تنها شامل همان کلاس D» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: L(B) , L(C)» و لیستی از superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: [B,C] +* **سطر ۱۱:** حاصل خطی سازی (linearization) کلاس D یا همان L(D) برابر است با «لیستی که تنها شامل همان کلاس D» ``+`` ادغام «حاصل خطی سازی (linearization) تک تک superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: L(B) , L(C)» و لیستی از superclassهای کلاس D با حفظ ترتیب از چپ به راست - در اینجا: [B,C] -* سطر ۱۲: حاصل L(B) و L(C) جایگذاری شده است. +* **سطر ۱۲:** حاصل L(B) و L(C) جایگذاری شده است. -* سطر ۱۳: اکنون عملیات ادغام شامل بیش از یک کلاس است، در این شرایط عملیات ادغام و انتخاب یک کلاس مطلوب آنقدر تکرار می‌شود تا دیگر کلاسی باقی نماند. فرآیند انتخاب کلاس مطلوب به این صورت است که از چپ‌ترین کلاس موجود در چپ‌ترین لیست شروع می‌کنیم به انتخاب، این کلاس می‌بایست در باقی لیست‌ها در صورت وجود چپ‌ترین عضو باشد، در غیر این صورت چپ‌ترین کلاس موجود در لیست بعدی انتخاب و بررسی خواهد شد. چنانچه کلاس انتخاب شده شرایط را دارا باشد عمل ادغام برای آن کلاس صورت می‌پذیرد و داخل تمام لیست‌ها در صورت وجود نیز حذف می‌گردد. در اینجا: ابتدا کلاس B انتخاب می‌شود، این کلاس شرایط مطلوب بودن را دارا می‌باشد، در نتیجه عمل ادغام برای آن به انجام می‌رسد. +* **سطر ۱۳:** اکنون عملیات ادغام شامل بیش از یک کلاس است، در این شرایط عملیات ادغام و انتخاب یک کلاس مطلوب آنقدر تکرار می‌شود تا دیگر کلاسی باقی نماند. فرآیند انتخاب کلاس مطلوب به این صورت است که از چپ‌ترین کلاس موجود در چپ‌ترین لیست شروع می‌کنیم به انتخاب، این کلاس می‌بایست در باقی لیست‌ها در صورت وجود چپ‌ترین عضو باشد، در غیر این صورت چپ‌ترین کلاس موجود در لیست بعدی انتخاب و بررسی خواهد شد. چنانچه کلاس انتخاب شده شرایط را دارا باشد عمل ادغام برای آن کلاس صورت می‌پذیرد و داخل تمام لیست‌ها در صورت وجود نیز حذف می‌گردد. در اینجا: ابتدا کلاس B انتخاب می‌شود، این کلاس شرایط مطلوب بودن را دارا می‌باشد، در نتیجه عمل ادغام برای آن به انجام می‌رسد. -* سطر ۱۴: در ادامه عمل ادغام فرآیند خطی سازی برای کلاس D، این بار ابتدا کلاس A انتخاب می‌شود، این کلاس شرایط لازم را ندارد چرا که در جایگاهی از لیست دوم نیز حضور دارد که جایگاه نخست (چپ‌ترین) نیست. کلاس A رها می‌شود و به سراغ لیست دوم می‌رویم، نخستین عضو آن یعنی کلاس C شرایط لازم برای ادغام را دارد، در نتیجه در این مرحله عمل ادغام برای کلاس C به انجام می‌رسد. +* **سطر ۱۴:** در ادامه عمل ادغام فرآیند خطی سازی برای کلاس D، این بار ابتدا کلاس A انتخاب می‌شود، این کلاس شرایط لازم را ندارد چرا که در جایگاهی از لیست دوم نیز حضور دارد که جایگاه نخست (چپ‌ترین) نیست. کلاس A رها می‌شود و به سراغ لیست دوم می‌رویم، نخستین عضو آن یعنی کلاس C شرایط لازم برای ادغام را دارد، در نتیجه در این مرحله عمل ادغام برای کلاس C به انجام می‌رسد. -* سطر ۱۵: حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با همان کلاس، در نتیجه کلاس A انتخاب و عمل ادغام برای آن به انجام می‌رسد. +* **سطر ۱۵:** حاصل ادغام چند لیست که تنها شامل یک کلاس می‌باشند برابر است با همان کلاس، در نتیجه کلاس A انتخاب و عمل ادغام برای آن به انجام می‌رسد. عملیات با موفقیت به پایان رسید و ما به مقداری برابر با ``__D.__mro`` دست پیدا کردیم! From 9cb22f7967bc8a5e617c2e441a63ab39f2befd26 Mon Sep 17 00:00:00 2001 From: Saeid Darvish Date: Fri, 12 Mar 2021 12:56:22 +0330 Subject: [PATCH 10/10] l18 --- lessons/l05.rst | 12 +++++++++++- lessons/l18.rst | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lessons/l05.rst b/lessons/l05.rst index d6d1fd9..d3482ee 100644 --- a/lessons/l05.rst +++ b/lessons/l05.rst @@ -7,7 +7,7 @@ درس ۰۵: مفهوم شی‌گرایی ======================== -این درس به توضیح مفاهیم پایه «برنامه‌نویسی شی‌گرا» اختصاص یافته است و آخرین درس از سطح‌بندی «پایه» در این کتاب می‌باشد. هدف از این درس آشنایی خوانندگان با مفاهیم عمومی شی‌گرایی بوده و نه آموزش آن؛ جزییات بیشتر از برنامه‌نویسی شی‌گرا به همراه آموزش پیاده‌سازی مفاهیم آن در زبان پایتون توسط درس‌هایی دیگر بررسی خواهد شد. در این درس همچنین به ساختار اشیا و کلاس‌ها در زبان پایتون اشاره‌ شده است که پیش‌نیاز دروس آتی خواهد بود. +این درس به توضیح مفاهیم پایه «برنامه‌نویسی شی‌گرا» اختصاص یافته است و آخرین درس از سطح‌بندی «پایه» در این کتاب می‌باشد. هدف از این درس آشنایی خوانندگان با مفاهیم عمومی شی‌گرایی بوده و نه آموزش آن؛ جزییات بیشتر از برنامه‌نویسی شی‌گرا به همراه آموزش پیاده‌سازی مفاهیم آن در زبان پایتون از درس هفدهم به بعد بررسی خواهد شد. در این درس همچنین به ساختار اشیا و کلاس‌ها در زبان پایتون اشاره‌ شده است که پیش‌نیاز دروس آتی خواهد بود. :emoji-size:`✔` سطح: پایه @@ -89,6 +89,11 @@ به عنوان نمونه سه کلاس «ماهی»، «گربه» و «کبوتر» را در نظر بگیرید. این کلاس‌ها جدا از رفتارهای خاص خود (مانند: «پرواز کردن» در کبوتر یا «شنا کردن» در ماهی)، در یک سری رفتار به مانند «نفس کشیدن»، «غذا خوردن» و... مشترک هستند. راه درستِ توسعه این کلاس‌ها تعیین یک «کلاس پایه» برای رفتارهای مشترک و ارث‌بری هر سه آن‌ها می‌باشد. ولی از آنجا که هر یک، این رفتارهای مشترک را به گونه‌ای دیگر انجام می‌دهد؛ راه درست‌تر آن است که یک «کلاس مجرد» به عنوان «کلاس پایه» آن‌ها در نظر بگیریم؛ در این حالت هر کدام از کلاس‌ها ضمن دانستن رفتارهای لازم می‌تواند آن‌‌ها را متناسب با خواست خود تعریف نماید. +.. note:: + + آنچه در ادامه این درس آورده شده است، چکیده‌ای از پیاده‌سازی برنامه‌نویسی شی گرا در پایتون است. شی گرایی در زبان برنامه نویسی پایتون به صورت کامل از درس هفدهم به بعد شرح داده می‌شود. + + اشیا در پایتون ---------------- @@ -269,6 +274,11 @@ +.. note:: + + آنچه در این درس آورده شده است، چکیده‌ای از پیاده‌سازی برنامه‌نویسی شی گرا در پایتون است. شی گرایی در زبان برنامه نویسی پایتون به صورت کامل از درس هفدهم به بعد شرح داده می‌شود. + + | ---- diff --git a/lessons/l18.rst b/lessons/l18.rst index 9674095..b820bbd 100644 --- a/lessons/l18.rst +++ b/lessons/l18.rst @@ -702,7 +702,7 @@ Aggregation :emoji-size:`😊` امیدوارم مفید بوده باشه -`لطفا دیدگاه و سوال‌های مرتبط با این درس خود را در کدرز مطرح نمایید. `_ +`لطفا دیدگاه و سوال‌های مرتبط با این درس خود را در کدرز مطرح نمایید. `_