Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fe771fa

Browse filesBrowse files
author
Saeid Darvish
committed
review Decorator
1 parent 0811a4e commit fe771fa
Copy full SHA for fe771fa

File tree

Expand file treeCollapse file tree

1 file changed

+120
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+120
-2
lines changed
Open diff view settings
Collapse file

‎lessons/l13.rst‎

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 numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
درس ۱۳: تابع - بخش دوم
99
========================
1010

11-
11+
این درس در ادامه درس پیش است که به معرفی مواردی از کاربردهای تابع در ایجاد مفاهیمی جدید، مهم و کاربردی در زبان برنامه‌نویسی پایتون می‌پردازد. مبحث تابع در پایتون با این درس به پایان نمی‌رسد و نکات باقی‌مانده در درس بعدی ارائه می‌شوند.
1212

1313

1414

@@ -32,7 +32,7 @@ Decorator
3232
----------
3333

3434

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‌ کلاس را در درس مربوط به کلاس‌ها بررسی خواهیم کرد.
3636

3737
برای پوشش یک تابع توسط Decorator‌ از سینتکسی مشابه ``decorator‌_name@`` در بالای بخش سرآیند استفاده می‌شود:
3838

@@ -198,6 +198,124 @@ Decorator
198198
>>>
199199

200200

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`` برایتان مبهم است به درس هفتم بخش مربوط به رشته‌ها مراجعه نمایید.
317+
318+
201319
Generator
202320
----------
203321

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.