Skip to content

Commit d382ef5

Browse files
author
Saeid Darvish
committed
l19: Metaclass is completed
1 parent ac30266 commit d382ef5

1 file changed

Lines changed: 55 additions & 3 deletions

File tree

lessons/l19.rst

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@
118118
119119
obj = self.__new__(self, *args, **kwargs)
120120
121-
if obj is not None and isinstance(obj, self) and hasattr(obj, '__init__'):
122-
obj.__init__(*args, **kwargs)
121+
obj.__init__(*args, **kwargs)
123122
124123
return obj
125124
@@ -169,15 +168,68 @@
169168
y: p_arg_2
170169
z: k_arg
171170

171+
بر اساس نمونه کد بالا، می‌توان فرآیند ایجاد یک شی در پایتون را به ترتیب زیر شرح داد:
172172

173+
* کلاس Sample فراخوانی می‌شود (سطر ۳۹)، در نتیجه به صورت خودکار متد ``__call__`` کلاسِ کلاس Sample یا همان متا کلاس آن (MetaClass) فراخوانی می‌شود. توجه داشته باشید که مقدار پارامتر ``self`` در این متد برابر با کلاس Sample می‌باشد (به خروجی سطر پنجم توجه شود - ``<'class '__main__.Sample>``)، چرا که شی فراخوانی کننده این متد اکنون خود کلاس Sample می‌باشد.
173174

175+
* داخل متد ``__call__`` از متا کلاس، ابتدا متد ``__new__`` تعریف شده داخل کلاس Sample فراخوانی می‌شود (سطر ۹). توجه داشته باشید که متد ``__new__`` از کلاس Sample نیز متد مرتبط از کلاس ``object`` (به عنوان superclass) فراخوانی شده است (سطر ۲۴). حاصل یک شی جدید از کلاس Sample خواهد بود که به داخل متد ``__call__`` از متاکلاس برگردانده می‌شود.
174176

177+
* داخل متد ``__call__`` از متا کلاس، اینبار متد ``__init__`` فراخوانی می‌گردد - پیش از برگرداندن شی Sample ایجاد شده (سطر ۱۱). این متد عملیات initialize یا مقداردهی اولیه را بر روی شی تازه ایجاد شده از کلاس Sample به انجام می‌رساند.
175178

179+
* در انتها متد ``__call__`` از متا کلاس، شی Sample را باز‌می‌گرداند (سطر ۱۳).
180+
181+
* توجه داشته باشید از آنجا که احتمال ارسال آرگومان به دو صورت «positional arguments» و «keyword arguments» وجود دارد، پارامترها و آرگومان‌ها به گونه‌ای تعریف و ارسال گردیدند که هر دو حالت پوشش داده شود:‌ ``args, **kwargs*``
182+
183+
با استفاده از مثال پیش، یک کاربرد جالب و مهم از قابلیت تعریف متا کلاس در پایتون را بررسی کردیم، مثالی که شما را با روند ایجاد شی نیز بیشتر آشنا کرد.
184+
185+
در انتهای این بخش جا دارد با امکان تعریف یک متد از نوع Class Method و نام ``__prepare__`` [`اسناد پایتون <https://docs.python.org/3/reference/datamodel.html#preparing-the-class-namespace>`__] در پایتون آشنا شویم. به صورت پیش‌فرض مفسر پایتون پس از اینکه متا کلاسِ یک کلاس را تشخیص می‌دهد، بلافاصله به دنبال ``__prepare__`` در آن می‌گردد و چنانچه پیاده‌سازی شده باشد، آن را فراخوانی و آرگومان‌های «متا کلاس»، «نام کلاسی که قرار است یک شی از آن ایجاد گردد»، «یک شی تاپل حاوی فهرست superclassهای آن کلاس - با حفظ ترتیب» و «تعدادی keyword argumentهای احتمالی (آرگومان‌های نام=مقدار)» را به آن ارسال می‌کند [`PEP 3115 <https://www.python.org/dev/peps/pep-3115/#invoking-the-metaclass>`__]. خروجی این متد می‌بایست یک شی دیکشنری (``dict``) باشد که در زمان ایجاد و ارزیابی کلاس، مورد استفاده قرار می‌گیرد. این متد قبل از ``__call__`` فراخوانی می‌شود و ما می‌توانیم از آن برای قرار دادن مقادیری برای استفاده در کلاس‌هایی که توسط متا کلاس ایجاد می‌گردند قرار دهیم. برای درک بهتر کاربرد این متد، به نمونه کد زیر توجه نمایید:
186+
187+
.. code-block:: python
188+
:linenos:
189+
190+
class MetaClass(type):
191+
192+
@classmethod
193+
def __prepare__(metacls, name, bases, **kwargs):
194+
print('\n------->>> MetaClass __prepare__')
195+
print('metaclass: ', metacls)
196+
print('name: ', name)
197+
print('superclasses: ', bases)
198+
print('extra arguments: ', kwargs)
199+
200+
return {"class_code": 1633}
201+
202+
203+
class Sample(metaclass=MetaClass):
204+
205+
@classmethod
206+
def print_extra_info(cls):
207+
print('\n------->>> Sample print_extra_info')
208+
209+
print ('class_code:', cls.__dict__['class_code'])
210+
211+
212+
print ('Sample.__dict__:\n', Sample.__dict__)
213+
Sample.print_extra_info()
214+
215+
::
216+
217+
------->>> MetaClass __prepare__
218+
metaclass: <class '__main__.MetaClass'>
219+
name: Sample
220+
superclasses: ()
221+
extra arguments: {}
222+
Sample.__dict__:
223+
{'class_code': 1633, '__module__': '__main__', 'print_extra_info': <classmethod object at 0x7f090a6aa5c0>, '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None}
224+
225+
------->>> Sample print_extra_info
226+
class_code: 1633
227+
228+
دانستن ترتیب مراحل فراخوانی متدهای معرفی شده و همچنین قابلیت پیاده‌سازی و شخصی‌سازی آن‌ها می‌تواند در شرایط خاص خودش برای برنامه‌نویس بسیار کارگشا باشد.
176229

177230

178231

179232

180-
بر اساس تعریف ارائه شده در [`اسناد پایتون <https://docs.python.org/3/glossary.html#term-metaclass>`__]، تعریف کلاس (دستور ``class``) باعث ایجاد «نام کلاس»، «یک شی دیکشنری از کلاس» و «یک شی لیست حاوی superclassهای آن کلاس» می‌شود، متاکلاس این سه آرگومان را دریافت و شی کلاس را ایجاد می‌کند.
181233

182234

183235

0 commit comments

Comments
 (0)