توابع دکوراتور (Decorator) یکی از قابلیتهای مهم در زبان برنامهنویسی پایتون هستند. این ابزار قدرتمند به برنامهنویسان امکان میدهد تا توابع خود را به سادگی تغییر دهند و عملکرد آنها را بهبود بخشند. توابع Decorator برای کارهایی مانند نظارت بر ورودیها، لاگگذاری، اندازهگیری زمان اجرا و بسیاری از کارهای دیگر مفید هستند. در این مقاله، ما با مفهوم توابع Decorator در پایتون آشنا خواهیم شد و نحوه استفاده از آنها را بررسی میکنیم.
مفهوم توابع Decorator
توابع دکوراتور (Decorators) در پایتون به عنوان یک نوع توابع معمولی تعریف میشوند. اما تفاوت اصلی آنها در این است که توابع دکوراتور قادر به تغییر رفتار توابع دیگر هستند. به عبارت دقیقتر، یک تابع دکوراتور توانایی اضافه کردن یک عملکرد اضافی به یک تابع دیگر را دارد، بدون اینکه کد تابع اصلی را تغییر دهد.
چرا از توابع دکوراتور استفاده میشود؟
استفاده از توابع دکوراتور دارای مزایا مختلفی است. در زیر چند دلیل برای استفاده از توابع دکوراتور در پایتون آوردهایم:
- جداسازی عملکرد: با استفاده از توابع دکوراتور، میتوانید عملکردهای مختلفی را به توابع اضافه کنید، به جای اینکه همه کد درون یک تابع بزرگ جا داده شود. این باعث افزایش خوانایی کد و تقسیم منطق برنامه به اجزای کوچکتر میشود.
- نظارت بر ورودیها: با توابع دکوراتور میتوانید ورودیهای یک تابع را بررسی کنید و اطمینان حاصل کنید که آنها از قوانین مشخصی پیروی میکنند. به عنوان مثال، یک توابع دکوراتور میتواند اعتبارسنجی ورودیها را انجام دهد و از ورودیهای نادرست جلوگیری کند.
- لاگگذاری (Logging): توابع دکوراتور معمولاً برای ثبت اطلاعات مربوط به اجرای توابع استفاده میشوند. این امر برای ارائه اطلاعات بهتر به منظور دیباگ و نظارت بر عملکرد برنامه مفید است.
- زمانبندی اجرا: با توابع دکوراتور میتوانید زمان اجرای یک تابع را اندازهگیری و اطلاعات مربوط به زمان اجرا را ثبت کنید. این اطلاعات میتواند برای بهبود عملکرد و بهینهسازی برنامه مفید باشد.
نحوه استفاده از توابع Decorator در پایتون
توابع Decorator در پایتون به عنوان یک توابع معمولی تعریف میشوند. برای استفاده از یک تابع دکوراتور ، شما باید آن را به عنوان یک دکوراتور به یک تابع دیگر اعمال کنید. برای این کار، شما از @
استفاده میکنید. دلیل استفاده از @
این است که کد توابع دکوراتور به تابع اصلی اضافه میشود.
مثال: تعریف یک تابع دکوراتور
def my_decorator(func):
def wrapper():
print("قبل از اجرای تابع")
func()
print("بعد از اجرای تابع")
return wrapper
@my_decorator
def say_hello():
print("سلام!")
say_hello()
در این مثال، ما یک تابع دکوراتور به نام my_decorator
تعریف کردهایم که یک تابع دیگر (func
) را صدا میزند. درون این تابع دکوراتور یک تابع دیگر به نام wrapper
تعریف کرده که قبل و بعد از اجرای تابع func
پیامهایی را چاپ میکند.
سپس با استفاده از @my_decorator
، ما تابع say_hello
را دکوراتور کردهایم. حالا اگر تابع say_hello
را فراخوانی کنیم، عملکرد آن توسط تابع دکوراتور my_decorator
تغییر میکند.
خروجی:
قبل از اجرای تابع
سلام!
بعد از اجرای تابع
توابع Decorator در پایتون با پارامتر
توابع دکوراتور میتوانند پارامترها را نیز بپذیرند و به توابع دیگر اعمال شوند. برای این کار، شما باید تعداد متغیرهای پارامتر تابع دکوراتور را مشخص کنید.
مثال: توابع دکوراتور با پارامتر
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num):
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(3)
def say_hello(name):
print(f"سلام، {name}!")
say_hello("آرمان")
مثال بالا، ما یک تابع دکوراتور به نام repeat
تعریف کردهایم که تعداد تکرار اجرای تابع دیگر (func
) را به عنوان پارامتر دریافت میکند. سپس درون خود تابع دکوراتور my_decorator
تعریف میکند که پارامترها را به تابع wrapper
منتقل میکند. تابع wrapper
مشابه مثال قبلی عمل کرده اما عملکرد تعداد تکرار تابع func
را مقدار مشخص شده در repeat
تعیین میکند.
سپس با استفاده از @repeat(3)
، ما تابع say_hello
را دکوراتور کردهایم و مقدار 3
به عنوان تعداد تکرار اجرای تابع مشخص کردهایم. حالا اگر تابع say_hello
را با یک پارامتر فراخوانی کنیم، عملکرد آن توسط تابع دکوراتور repeat
تغییر خواهد کرد.
خروجی:
سلام، آرمان!
سلام، آرمان!
سلام، آرمان!
توابع دکوراتور چند لایه
میتوانید چندین تابع دکوراتور را به یک تابع اعمال کنید. در این صورت، توابع دکوراتور به ترتیب اعمال میشوند. این ترتیب را در مثال بعدی خواهید دید.
مثال: توابع دکوراتور چند لایه
def decorator1(func):
def wrapper():
print("تابع دکوراتور 1: قبل از اجرای تابع")
func()
print("تابع دکوراتور 1: بعد از اجرای تابع")
return wrapper
def decorator2(func):
def wrapper():
print("تابع دکوراتور 2: قبل از اجرای تابع")
func()
print("تابع دکوراتور 2: بعد از اجرای تابع")
return wrapper
@decorator1
@decorator2
def say_hello():
print("سلام!")
say_hello()
در این مثال، ما دو تابع دکوراتور به نام decorator1
و decorator2
تعریف کردهایم. هر کدام از این توابع دکوراتور یک تابع دیگر را به عنوان ورودی دریافت میکنند و تغییراتی بر روی عملکرد آن اعمال میکنند.
سپس با استفاده از @decorator1
و @decorator2
، ما تابع say_hello
را دکوراتور کردهایم. حالا اگر تابع say_hello
را فراخوانی کنیم، توابع دکوراتور به ترتیب اعمال میشوند و عملکرد تابع say_hello
تغییر میکند.
خروجی:
تابع دکوراتور 1: قبل از اجرای تابع
تابع دکوراتور 2: قبل از اجرای تابع
سلام!
تابع دکوراتور 2: بعد از اجرای تابع
تابع دکوراتور 1: بعد از اجرای تابع
توابع دکوراتور سفارشی
میتوانید توابع دکوراتور سفارشی خود را تعریف کنید و از آنها برای تغییر عملکرد توابع استفاده کنید. این توابع دکوراتور سفارشی میتوانند به تواناییهای شما در ایجاد کدهای بزرگتر و پیچیدهتر کمک کنند.
مثال: توابع دکوراتور سفارشی
def custom_decorator(prefix):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix}: قبل از اجرای تابع")
func(*args, **kwargs)
print(f"{prefix}: بعد از اجرای تابع")
return wrapper
return decorator
@custom_decorator("دکوراتور 1")
def say_hello():
print("سلام!")
@custom_decorator("دکوراتور 2")
def say_goodbye():
print("خداحافظ!")
say_hello()
say_goodbye()
در این مثال، ما یک تابع دکوراتور سفارشی به نام custom_decorator
تعریف کردهایم که یک پیشوند (مثل “تزئینی 1” یا “تزئینی 2”) را به عنوان ورودی میپذیرد. سپس این تابع دکوراتور سفارشی یک تابع دکوراتور ایجاد میکند که عملکردی مشابه مثالهای قبلی دارد.
سپس با استفاده از @custom_decorator("تزئینی 1")
و @custom_decorator("تزئینی 2")
، ما توابع say_hello
و say_goodbye
را دکوراتور کردهایم. حالا اگر این دو تابع را فراخوانی کنیم، توابع دکوراتور با پیشوندهای مختلف به ترتیب اعمال میشوند و عملکرد هر تابع تغییر میکند.
خروجی:
دکوراتور 1: قبل از اجرای تابع
سلام!
دکوراتور 1: بعد از اجرای تابع
دکوراتور 2: قبل از اجرای تابع
خداحافظ!
دکوراتور 2: بعد از اجرای تابع
توابع دکوراتور قبل و بعد
با استفاده از توابع دکوراتور میتوانید عملکرد یک تابع را قبل یا بعد از اجرا تغییر دهید. به این ترتیب، میتوانید کدهای پیچیدهتری ایجاد کنید که به توابع اصلی خود عملکرد اضافی اعمال میکنند.
مثال: توابع دکوراتور قبل و بعد
def before_and_after(func):
def wrapper(*args, **kwargs):
print("قبل از اجرای تابع")
result = func(*args, **kwargs)
print("بعد از اجرای تابع")
return result
return wrapper
@before_and_after
def say_hello():
print("سلام!")
result = say_hello()
print(f"نتیجه: {result}")
در این مثال، ما یک تابع دکوراتور به نام before_and_after
تعریف کردهایم که عملکرد یک تابع را تغییر میدهد. این تابع دکوراتور یک تابع دیگر را به عنوان ورودی دریافت میکند و در داخل آن، قبل از اجرای تابع اصلی یک پیام چاپ میکند و بعد از اجرای تابع اصلی نیز یک پیام دیگر چاپ میکند.
سپس با استفاده از @before_and_after
، ما تابع say_hello
را دکوراتور کردهایم. حالا اگر تابع say_hello
را فراخوانی کنیم، عملکرد آن توسط تابع دکوراتور before_and_after
تغییر خواهد کرد.
خروجی:
قبل از اجرای تابع
سلام!
بعد از اجرای تابع
نتیجه: None
استفاده از توابع دکوراتور در واقعیت
توابع دکوراتور یکی از ابزارهای قدرتمند در پایتون هستند که به برنامهنویسان امکان میدهند تا عملکرد توابع را تغییر دهند و کدهای تکراری را کاهش دهند. با استفاده از توابع دکوراتور ، میتوانید منطق برنامه خود را به طور شفافتر ارتقا دهید و کد بهتری ایجاد کنید.
از آنجا که توابع دکوراتور میتوانند به تعداد بیپایانی توالی شوند، باید مراقب باشید تا باعث پیچیدگی زیاد در کدهای خود نشوید. همچنین، توجه داشته باشید که توابع دکوراتور اغلب منطق برنامه را به شکل مخفی تغییر میدهند، بنابراین باید با دقت آنها را طراحی و استفاده کنید.
در پایان، توابع دکوراتور ابزار قدرتمندی هستند که به شما امکان میدهند کدتان را تمیزتر و قابلمدیریتتر کنید. شما میتوانید از آنها برای ایجاد کدهای پیچیدهتر و توسعهپذیرتری در پروژههای خود بهرهبرداری کنید