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 ارسال میگردد. دو نمونه کد زیر معادل یکدیگر هستند::
در زبان برنامهنویسی پایتون میتوان از کلاسها همچون توابع برای ایجاد Decorator استفاده کرد. در این صورت شیای که Decorator به آن اعمال شده است از طریق متد ``__init__`` دریافت میگردد. همچنین میبایست متد ``__call__`` را پیادهسازی کرده باشیم تا اشیای کلاس قابلیت callable را داشته باشند (درس هفدهم)، عملیات اصلی Decorator میبایست داخل این متد پیادهسازی گردد:
394
+
395
+
396
+
397
+
::
398
+
399
+
class CountCalls:
400
+
def __init__(self, func):
401
+
self.func = func
402
+
self.num_calls = 0
403
+
404
+
def __call__(self):
405
+
self.num_calls += 1
406
+
print(f"Call {self.num_calls} of {self.func.__name__!r}")
407
+
return self.func()
408
+
409
+
::
410
+
411
+
# 1
412
+
413
+
@CountCalls
414
+
def func():
415
+
''' a function'''
416
+
417
+
print(func.__doc__)
418
+
func()
419
+
func()
420
+
421
+
422
+
::
423
+
424
+
# 2
425
+
426
+
def func():
427
+
''' a function'''
428
+
429
+
obj = CountCalls(func)
430
+
431
+
print(obj.__doc__)
432
+
obj()
433
+
obj()
434
+
435
+
436
+
::
437
+
438
+
439
+
# Output
440
+
441
+
None
442
+
Call 1 of 'func'
443
+
Call 2 of 'func'
444
+
445
+
446
+
447
+
**functools.update_wrapper**
448
+
449
+
همانند کاربرد تابع ``wraps`` از ماژول ``functools`` در هنگام ساخت Decorator از توابع، در اینجا نیز میتوانیم جهت حفظ اطلاعات مربوط به تابع اصلی، اینبار از تابع ``update_wrapper`` این ماژول استقاده کنیم [`اسناد پایتون <https://docs.python.org/3/library/functools.html#functools.update_wrapper>`__] - اگر کلاس CountCalls را به صورت زیر تغییر دهیم، آنگاه خروجی هر دو حالت نیز به شرح زیر تغییر خواهد کرد، چرا که اکنون ``__doc__`` در دسترس باقی مانده است::
450
+
451
+
452
+
import functools
453
+
454
+
class CountCalls:
455
+
def __init__(self, func):
456
+
functools.update_wrapper(self, func)
457
+
self.func = func
458
+
self.num_calls = 0
459
+
460
+
def __call__(self):
461
+
self.num_calls += 1
462
+
print(f"Call {self.num_calls} of {self.func.__name__!r}")
0 commit comments