You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
از درس سیزدهم با مفهوم Decoratorها و نیز کاربرد آنها به همراه تابع در زبان برنامهنویسی پایتون آشنا شدهایم، در این بخش به بررسی Decoratorهابه همراه کلاسها و متدها میپردازیم.
31
+
32
+
علاوه بر اینکه با استفاده از کلاس میتوان یک Decorator ایجاد کرد، از Decoratorها نیز میتوان بر روی کلاس یا متدهای داخل یک کلاس بهره گرفت. در ادامه به بررسی این موارد میپردازیم.
این کار همانند قراردادن Decorator بر روی تابع میباشد (درس سیزدهم) و تفاوتی ندارد. پیشتر نیز از Decoratorهایی همچون ``classmethod@`` یا ``staticmethod@`` بر روی متدها استفاده میکردیم. به مثالی در همین زمینه توجه نمایید:
kwargs_repr = [f"{k}={v!r}"for k, v in kwargs.items()]
54
+
signature =", ".join(args_repr + kwargs_repr)
55
+
print(f"Calling {func.__name__}({signature})")
56
+
value = func(*args, **kwargs)
57
+
print(f"{func.__name__!r} returned {value!r}")
58
+
return value
59
+
return wrapper_debug
60
+
61
+
62
+
63
+
classSample:
64
+
65
+
@debug
66
+
def__init__(self, x=0, y=0):
67
+
self.x = x
68
+
self.y = y
69
+
70
+
71
+
sample = Sample(5, y=6)
72
+
73
+
::
74
+
75
+
Calling __init__(<__main__.Sample object at 0x7fd96ddec8d0>, 5, y=6)
76
+
'__init__' returned None
77
+
78
+
در نمونه کد بالا یک Decorator با نام ``debug`` ایجاد گردیده است (Decorator درس سیزدهم و f-string درس هفتم)، با قراردادن این Decorator بر روی یک تابع یا متد: نام تابع، آرگومانهای ارسال شده و همچنین مقدار خروجی تابع را بر روی خروجی نمایش میدهد.
از **نسخه 3.7 پایتون** یک ویژگی جالب به پایتون اضافه گردید. دیتا کلاس **(Data Class)**، در واقع یک سینتکسی سادهسازی شده برای ایجاد کلاسهایی که معمولا تنها حاوی Instance Attribute میباشند. این نوع کلاس با استفاده از دکوراتور ``dataclass@`` از ماژول ``dataclasses`` ایجاد میگردد [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html>`__]. برای مثال کلاس زیر را در نظر بگیرید:
106
+
از **نسخه 3.7 پایتون** یک ویژگی جالب به پایتون اضافه گردید. دیتا کلاس **(Data Class)** [`PEP 557 <https://www.python.org/dev/peps/pep-0557>`__]، در واقع یک سینتکسی سادهسازی شده برای ایجاد کلاسهایی که معمولا تنها حاوی Instance Attribute میباشند. این نوع کلاس با استفاده از دکوراتور ``dataclass@`` از ماژول ``dataclasses`` ایجاد میگردد [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html>`__]. برای مثال کلاس زیر را در نظر بگیرید:
31
107
32
108
33
109
.. code-block:: python
@@ -60,7 +136,7 @@ Data Classes
60
136
61
137
در این نوع کلاس برای تعریف Attributeها از سینتکس Variable Annotations [`PEP 526 <https://www.python.org/dev/peps/pep-0526/>`__] استفاده میشود. این سینتکس و در کل ذکر نوع داده در پایتون یا Type Hints [`PEP 484 <https://www.python.org/dev/peps/pep-0484/>`__] **موضوع درس بعدی است**. در این شیوه نوع متغیرها به صراحت ذکر میگردد. در حالت عادی تعریف یک متغییر در زبان برنامهنویسی پایتون به صورت ``var = value`` میباشد (درس ششم)، همانطور که میدانیم تاکنون هیچگاه در پایتون برای تعریف متغییر نیازی به ذکر صریح نوع داده نمیبود، **اکنون نیز نیازی نیست**، ولی از **نسخه 3.6 پایتون** میتوانیم اینکار را انجام دهیم، میتوانیم نوع داده را خودمان مشخص کنیم یا به اصطلاح آن نوع را annotation کنیم. سینتکس این عملیات به صورت ``var: annotation`` میباشد، این سینتکس مشخص میکند که متغییر var از نوع annotation میباشد. همچنین با استفاده از سینتکس ``var: annotation = value`` نیز میتوان همزمان عملیات انتساب و مقداردهی را نیز انجام داد. باید توجه داشت که تغییری در ساختار مفسر پایتون ایجاد نشده است!، بلکه صرفا سینتکس جدیدی اضافه شده که میتواند به ابزارهای شخصثالث (third party) همانند IDEها برای کنترل نوع دادهها در زمان توسعه برنامه یاریرسان باشد.
62
138
63
-
باید توجه داشت که طبق سند PEP 484 پیروی از اصول Type Hints در پایتون اجباری نبوده و نخواهد شد. ولی Data Class یک استثناست و در آن حتما میبایست Attributeها به شیوه شرح داده شده، تعریف گردند.
139
+
باید توجه داشت که طبق سند PEP 484 پیروی از اصول Type Hints در پایتون اجباری نبوده و نخواهد شد. ولی Data Class یک استثناست و در آن حتما میبایست Attributeها به شیوه شرح داده شده، تعریف گردند و به آنها فیلدهای (field) دیتا کلاس گفته میشود.
64
140
65
141
از آنجا که این نوع کلاس برای ایجاد یک کاربرد عمومی از کلاسها توسعه یافته (نگهداری اطلاعات)، بنابراین بسیاری از عملیاتها در آن خودکارسازی شده تا پیادهسازی این کلاس سادهتر از هر کلاس دیگری باشد. برای مثال نیازی به پیادهسازی متد ``__init__`` نیست و این متد به صورت خودکار برای کلاس ما ایجاد میگردد. اکنون اگر بخواهیم دیتاکلاس مثال قبل را به صورت عادی پیادهسازی کنیم:
66
142
@@ -167,7 +243,7 @@ Data Classes
167
243
168
244
169
245
170
-
از طریق ماژول ``dataclasses`` یک نوع یک annotation type جدید با نام ``InitVar`` در دسترس است. چنانچه در تعریف هر یک از Attributeها کلاس از این نوع استفاده کنیم، آن Attribute به عنوان پارامتر به متد ``__post_init__`` ارسال میگردد. باید توجه داشت که این نوع Attributeها به عنوان **Init-only variables** شناخته میشوند [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html#init-only-variables>`__] و مفسر پایتون آنها را صرفا به ``__post_init__`` ارسال میکند و جزو فیلدهای دیتا کلاس قرار نمیدهد:
246
+
از طریق ماژول ``dataclasses`` یک نوع یک annotation type جدید با نام ``InitVar`` در دسترس است. چنانچه در تعریف هر یک از Attributeها کلاس از این نوع استفاده کنیم، آن Attribute به عنوان پارامتر به متد ``__post_init__`` ارسال میگردد. باید توجه داشت که این نوع Attributeها به عنوان **Init-only variables** شناخته میشوند [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html#init-only-variables>`__] و مفسر پایتون آنها را صرفا به ``__post_init__`` ارسال میکند و **جزو فیلدهای دیتا کلاس قرار نمیدهد**:
171
247
172
248
173
249
.. code-block:: python
@@ -193,85 +269,65 @@ Data Classes
193
269
Student(score=100)
194
270
195
271
196
-
تابع ``fields``
272
+
تابع ``field`` و ``fields``
197
273
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
198
274
199
-
200
-
201
-
202
-
Decorators
203
-
----------------------------
204
-
205
-
از درس سیزدهم با مفهوم Decoratorها و نیز کاربرد آنها به همراه تابع در زبان برنامهنویسی پایتون آشنا شدهایم، در این بخش به بررسی Decoratorهابه همراه کلاسها و متدها میپردازیم.
206
-
207
-
علاوه بر اینکه با استفاده از کلاس میتوان یک Decorator ایجاد کرد، از Decoratorها نیز میتوان بر روی کلاس یا متدهای داخل یک کلاس بهره گرفت. در ادامه به بررسی این موارد میپردازیم.
این کار همانند قراردادن Decorator بر روی تابع میباشد (درس سیزدهم) و تفاوتی ندارد. پیشتر نیز از Decoratorهایی همچون ``classmethod@`` یا ``staticmethod@`` بر روی متدها استفاده میکردیم. به مثالی در همین زمینه توجه نمایید:
214
-
275
+
تابع ``fields`` از ماژول ``dataclasses`` یک شی از دیتا کلاس یا خود دیتا کلاس را از ورودی دریافت و یک تاپل حاوی تمام فیلدهای آن بر میگرداند [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html#dataclasses.fields>`__]:
from dataclasses import dataclass, InitVar, fields
224
281
225
-
@functools.wraps(func)
226
-
defwrapper_debug(*args, **kwargs):
227
-
args_repr = [repr(a) for a in args]
228
-
kwargs_repr = [f"{k}={v!r}"for k, v in kwargs.items()]
229
-
signature =", ".join(args_repr + kwargs_repr)
230
-
print(f"Calling {func.__name__}({signature})")
231
-
value = func(*args, **kwargs)
232
-
print(f"{func.__name__!r} returned {value!r}")
233
-
return value
234
-
return wrapper_debug
282
+
@dataclass
283
+
classStudent:
284
+
name: str
285
+
score: int=70
286
+
age: InitVar[int] =18
235
287
236
288
289
+
obj = Student('saeid', 90, 20)
290
+
print(obj)
291
+
print(fields(obj))
237
292
238
-
classSample:
293
+
::
239
294
240
-
@debug
241
-
def__init__(self, x=0, y=0):
242
-
self.x = x
243
-
self.y = y
295
+
Student(name='saeid', score=90)
296
+
(Field(name='name',type=<class 'str'>,default=<dataclasses._MISSING_TYPE object at 0x7f7e5c68cd68>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f7e5c68cd68>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD), Field(name='score',type=<class 'int'>,default=70,default_factory=<dataclasses._MISSING_TYPE object at 0x7f7e5c68cd68>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD))
244
297
245
298
246
-
sample = Sample(5, y=6)
299
+
پیشتر گفتیم، Attributeهای داخل یک دیتا کلاس فیلد (Field) خوانده میشوند. خروجی بالا نمایش ساختار یک شی Field از دیتا کلاس میباشد [`اسناد پایتون <https://docs.python.org/3/library/dataclasses.html#dataclasses.field>`__]. در واقع متغیرهایی که داخل دیتا کلاس با سنتکس Variable Annotations تعریف میشوند، به صورت خودکار به فیلد (Field) تبدیل میشوند. فیلدها میتوانند حاوی مقدار پیشفرض باشند (همانند فیلد ``score``). برای کاستن از حجم functionality داخل یک دیتا کلاس، ماژول ``dataclasses`` پایتون شامل تابعی است با نام ``field`` که توانایی و انعطاف زیادی در فراهم آوردن مقدار پیشفرض برای فیلدهای تعریف شده ایجاد میکند.
247
300
248
-
::
301
+
یک شی فیلد شامل پارامترهایی است که از طریق تابع ``field`` قابل تنظیم هستند، البته به جز دو پارامتر زیر که از تعریف Variable Annotations استنباط میشوند:
249
302
250
-
Calling __init__(<__main__.Sample object at 0x7fd96ddec8d0>, 5, y=6)
251
-
'__init__' returned None
252
303
253
-
در نمونه کد بالا یک Decorator با نام ``debug`` ایجاد گردیده است (Decorator درس سیزدهم و f-string درس هفتم)، با قراردادن این Decorator بر روی یک تابع یا متد: نام تابع، آرگومانهای ارسال شده و همچنین مقدار خروجی تابع را بر روی خروجی نمایش میدهد.
304
+
* ``name``: نام فیلد
254
305
306
+
* ``type``: نوع (type) فیلد
255
307
308
+
**تعریف مقدار پیشفرض برای یک فیلد با استفاده از تابع** ``field``::
* توجه: همانطور که از مبحث Keyword-Only Arguments از درس دوازدهم به یاد داریم، فراخوانی این تابع تنها با استفاده از ارسال آرگومان به صورت نام=مقدار مجاز خواهید بود.
* ``default``: مقدار پیشفرض فیلد، در صورت عدم نیاز میبایست با مقدار ویژه ``MISSING`` مقداردهی گردد.
264
316
317
+
* ``default_factory``: یک موجودیت callable بدون آرگومان را دریافت میکند و در زمانی که به مقدار پیشفرض برای فیلد نیاز باشد، فراخوانی میگردد. در صورت عدم نیاز میبایست با مقدار ویژه ``MISSING`` مقداردهی گردد. به بیانی دیگر میتوان با استفاده از این پارامتر، یک تابع به فیلد اختصاص داد که مقدار یا مقادیر پیشفرضی را برای فیلد مورد نظر تولید نماید.
265
318
319
+
* توجه: در هر فیلد تنها یکی از دو پارامتر ``default`` یا ``default_factory`` میبایست حاوی مقداری غیر از ``MISSING`` باشد.
266
320
267
-
Descriptors
268
-
----------------------------
269
321
322
+
* ``repr``, ``init``, ``compare``, ``hash``: در صورتی که هر کدام از این پارامترها برابر با مقدار ``True`` (پیشفرض) تنطیم گردند، فیلد مربوطه به متدهای ایجاد شده متناظر با هر پارامتر ارسال خواهد شد::
* توجه چنانچه مقدار ``compare`` برای ``True`` تنظیم گردد (حالت پیشفرض)،مقدار ``hash`` میبایست ``None`` (و نه ``False``) باشد، چرا که عملیات مقایسه دو شی دیگر به مقدار hash وابسته نبوده و از طریق متدهای تولید شده (__eq__ و غیره) انجام خواهد شد.
0 commit comments