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
Copy file name to clipboardExpand all lines: lessons/l13.rst
+120-2Lines changed: 120 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@
8
8
درس ۱۳: تابع - بخش دوم
9
9
========================
10
10
11
-
11
+
این درس در ادامه درس پیش است که به معرفی مواردی از کاربردهای تابع در ایجاد مفاهیمی جدید، مهم و کاربردی در زبان برنامهنویسی پایتون میپردازد. مبحث تابع در پایتون با این درس به پایان نمیرسد و نکات باقیمانده در درس بعدی ارائه میشوند.
12
12
13
13
14
14
@@ -32,7 +32,7 @@ Decorator
32
32
----------
33
33
34
34
35
-
دکوراتور (تزئینگر) یا همان **Decorator** ها [`PEP 318 <https://www.python.org/dev/peps/pep-0318//>`__] به توابعی گفته میشود که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا با کاهش حجم کدنویسی و بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد. در این بخش تمرکز بر روی اعمال Decoratorها به توابع است و Decorator کلاس را در درس مربوط به کلاسها بررسی خواهیم کرد.
35
+
دکوراتور (تزئینگر) یا همان **Decorator** ها [`PEP 318 <https://www.python.org/dev/peps/pep-0318//>`__] به توابعی گفته میشود که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا با کاهش حجم کدنویسی و بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد. در این بخش تمرکز بر روی **اعمال** Decoratorها به **توابع** است و Decorator کلاس را در درس مربوط به کلاسها بررسی خواهیم کرد.
36
36
37
37
برای پوشش یک تابع توسط Decorator از سینتکسی مشابه ``decorator_name@`` در بالای بخش سرآیند استفاده میشود:
38
38
@@ -198,6 +198,124 @@ Decorator
198
198
>>>
199
199
200
200
201
+
**functools.wraps@**
202
+
======================
203
+
204
+
در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی ارائه میدهد [`مستندات پایتون <https://docs.python.org/3/library/functools.html>`__]. یکی از این توابع ``wraps`` [`مستندات پایتون <https://docs.python.org/3/library/functools.html#functools.wraps>`__] میباشد.
205
+
206
+
اما چرا معرفی این تابع در این بخش مهم است؟. وقتی ما از یک Decorator استفاده میکنیم، اتفاقی که میافتد این است که یک تابع جدید جایگزین تابع اصلی ما میشود. به نمونه کدهای پایین توجه نمایید::
207
+
208
+
>>> def func(x):
209
+
... """does some math"""
210
+
... return x + x * x
211
+
...
212
+
>>>
213
+
>>> print(func.__name__)
214
+
func
215
+
>>> print(func.__doc__)
216
+
does some math
217
+
>>>
218
+
219
+
::
220
+
221
+
>>> def logged(func):
222
+
... def with_logging(*args, **kwargs):
223
+
... print(func.__name__ + " was called")
224
+
... return func(*args, **kwargs)
225
+
... return with_logging
226
+
...
227
+
>>>
228
+
>>> @logged
229
+
... def f(x):
230
+
... """does some math"""
231
+
... return x + x * x
232
+
...
233
+
>>>
234
+
>>> print(f.__name__)
235
+
with_logging
236
+
>>> print(f.__doc__)
237
+
None
238
+
>>>
239
+
240
+
::
241
+
242
+
>>> # It is mean: f = logged(func)
243
+
...
244
+
>>> f = logged(func)
245
+
>>> print(f.__name__)
246
+
with_logging
247
+
248
+
در زمان استفاده Decorator وقتی خواستیم نام تابع را چاپ کنیم ``(__print(f.__name`` نام تابع جدید (``with_logging``) چاپ شد و نه تابع اصلی (``f``).
249
+
250
+
استفاده از Decorator همیشه به معنی از دست رفتن اطلاعات مربوط به تابع اصلی است که به منظور جلوگیری از این اتفاق و حفظ اطلاعات مربوط به تابع اصلی خود میتوانیم از تابع ``wraps`` استفاده کنیم. این تابع در واقع خود یک Decorator است که وظیفه آن کپی اطلاعات از تابعی که به عنوان آرگومان دریافت میکند به تابعی که به آن انتساب داده شده است::
251
+
252
+
>>> from functools import wraps
253
+
>>>
254
+
>>> def logged(func):
255
+
... @wraps(func)
256
+
... def with_logging(*args, **kwargs):
257
+
... print(func.__name__ + " was called")
258
+
... return func(*args, **kwargs)
259
+
... return with_logging
260
+
...
261
+
>>>
262
+
>>> @logged
263
+
... def f(x):
264
+
... """does some math"""
265
+
... return x + x * x
266
+
...
267
+
>>>
268
+
>>> print(f.__name__)
269
+
f
270
+
>>> print(f.__doc__)
271
+
does some math
272
+
>>>
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
لطفا به آخرین مثال از بحث Decorator نیز توجه فرمایید. در این مثال زمان اجرای یک تابع را با استفاده از Decoratorها محاسبه خواهیم کرد [`منبع <https://realpython.com/primer-on-python-decorators/#a-few-real-world-examples>`__]::
284
+
285
+
>>> import functools
286
+
>>> import time
287
+
>>>
288
+
>>> def timer(func):
289
+
... """Print the runtime of the decorated function"""
290
+
... @functools.wraps(func)
291
+
... def wrapper_timer(*args, **kwargs):
292
+
... start_time = time.perf_counter()
293
+
... value = func(*args, **kwargs)
294
+
... end_time = time.perf_counter()
295
+
... run_time = end_time - start_time
296
+
... print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
297
+
... return value
298
+
... return wrapper_timer
299
+
...
300
+
>>>
301
+
>>> @timer
302
+
... def waste_some_time(num_times):
303
+
... result = 0
304
+
... for _ in range(num_times):
305
+
... for i in range(10000)
306
+
... result += i**2
307
+
...
308
+
>>>
309
+
>>> waste_some_time(1)
310
+
Finished 'waste_some_time' in 0.0072 secs
311
+
>>> waste_some_time(999)
312
+
Finished 'waste_some_time' in 2.6838 secs
313
+
314
+
در این مثال از تابع ``perf_counter`` برای محاسبه فواصل زمانی (time intervals) [`مستندات پایتون <https://docs.python.org/3/library/time.html#time.perf_counter>`__] استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی <https://stackoverflow.com/a/25787875/8434370>`__].
315
+
316
+
چنانچه درک دستور ``("print(f"Finished {func.__name__!r} in {run_time:.4f} secs`` برایتان مبهم است به درس هفتم بخش مربوط به رشتهها مراجعه نمایید.
0 commit comments