دکوراتور ها (Decorators)
«دکوراتور پایتون (Python Decorator)» یعنی رفتار اضافه بدهیم، بدون تغییر کد تابع. دکوراتور خودش یک تابع است. این تابع، یک تابع دیگر می گیرد و یک تابع تازه برمی گرداند. مثل برچسبی که بالا سر تابع می چسبانیم.
دکوراتور پایه
اول دکوراتور را تعریف کن. سپس با علامت @name روی تابع بچسبان.
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Hello Sally"
print(myfunction())
نکته: changecase دکوراتور است. myfunction تابع تزئین شده است. برای آشنایی با داده ورودی، صفحه آرگومان ها را ببین.
استفاده چندباره
یک دکوراتور را می توان روی چند تابع گذاشت. فقط آن را بالای هر تابع بنویس.
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Hello Sally"
@changecase
def otherfunction():
return "I am speed!"
print(myfunction())
print(otherfunction())
تابع تزئین شده با آرگومان
اگر تابعت ورودی دارد، ورودی را به «wrapper» بده. «wrapper» همان تابع داخلیِ دکوراتور است.
def changecase(func):
def myinner(x):
return func(x).upper()
return myinner
@changecase
def myfunction(nam):
return "Hello " + nam
print(myfunction("John"))
پشتیبانی از *args و **kwargs
گاهی نوع و تعداد ورودی ها معلوم نیست. پس *args و **kwargs را به «wrapper» اضافه کن تا هر ورودی را عبور دهد. برای جزئیات بیشتر به *args / **kwargs برو.
def changecase(func):
def myinner(*args, **kwargs):
return func(*args, **kwargs).upper()
return myinner
@changecase
def myfunction(nam):
return "Hello " + nam
print(myfunction("John"))
دکوراتور با آرگومان خودش
می خواهی دکوراتور تنظیم داشته باشد؟ یک لایه دیگر بساز. لایه بیرونی تنظیم می گیرد و دکوراتور می سازد.
def changecase(n):
def changecase(func):
def myinner():
if n == 1:
a = func().lower()
else:
a = func().upper()
return a
return myinner
return changecase
@changecase(1)
def myfunction():
return "Hello Linus"
print(myfunction())
چند دکوراتور روی یک تابع
می توان چند دکوراتور را روی هم گذاشت. اجرا از نزدیک ترین به تابع شروع می شود.
def changecase(func):
def myinner():
return func().upper()
return myinner
def addgreeting(func):
def myinner():
return "Hello " + func() + " Have a good day!"
return myinner
@changecase
@addgreeting
def myfunction():
return "Tobias"
print(myfunction())
حفظ نام و راهنما با wraps
تابع ها اطلاعاتی مثل __name__ و __doc__ دارند. با دکوراتور، این ها گم می شوند. برای حفظشان از functools.wraps استفاده کن.
def myfunction():
return "Have a great day!"
print(myfunction.__name__)
def changecase(func):
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Have a great day!"
print(myfunction.__name__)
import functools
def changecase(func):
@functools.wraps(func)
def myinner():
return func().upper()
return myinner
@changecase
def myfunction():
return "Have a great day!"
print(myfunction.__name__)
نکته: برای پیوند رفتارها با متغیرها، صفحه حوزه دسترسی مفید است. اگر به توابع کوچک علاقه داری، صفحه بعدی «لامبدا» نیز مرتبط است.
گام های عملی
- یک دکوراتور ساده بنویس و خروجی را تغییر بده.
- آن را روی چند تابع امتحان کن.
- پشتیبانی
*argsو**kwargsاضافه کن. - با
wrapsنام تابع را نگه دار.
جمع بندی سریع
- دکوراتور رفتار اضافه می دهد.
- @name را بالای تابع بگذار.
- *args و **kwargs ورودی ها را پوشش می دهند.
- wraps نام و توضیح را حفظ می کند.