دکوراتورها (Decorators) در پایتون
دکوراتورها یکی از امکانات قدرتمند پایتون برای افزودن یا تغییر رفتار توابع (یا کلاسها) بدون نیاز به ویرایش مستقیم آنها هستند. این ویژگی زمانی مفید است که بخواهید عملکرد تابعی را گسترش دهید، بدون اینکه محتوای اصلی آن تابع را تغییر دهید.
مثال ساده از دکوراتور
def my_decorator(func):
def wrapper():
print("Before the function runs")
func()
print("After the function runs")
return wrapper
def say_hello():
print("Hello!")
decorated = my_decorator(say_hello)
decorated()
در این مثال، تابع my_decorator
یک تابع ورودی میگیرد و یک تابع داخلی به نام wrapper
برمیگرداند که اجرای تابع اصلی را با مقداری کد اضافی قبل و بعد از آن تزئین میکند. سپس این دکوراتور را روی تابع say_hello
اعمال کردهایم.
استفاده از @ برای دکوراتورها
پایتون راهی میانبر برای استفاده از دکوراتورها فراهم کرده است. به جای ساخت متغیر جدید، میتوانید با علامت @
مستقیماً دکوراتور را روی تابع اعمال کنید:
@my_decorator
def say_hello():
print("Hello!")
say_hello()
دکوراتور با پارامتر ورودی
برای توابعی که دارای پارامتر هستند، دکوراتور باید از *args
و **kwargs
برای پشتیبانی از تعداد دلخواه آرگومان استفاده کند:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
return func(*args, **kwargs)
return wrapper
@logger
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
مثال عملیتر: محاسبه زمان اجرای یک تابع
در مثال زیر از یک دکوراتور برای اندازهگیری زمان اجرای یک تابع استفاده میکنیم:
import time
def timing(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} executed in {end - start:.4f} seconds")
return result
return wrapper
@timing
def slow_function():
time.sleep(2)
print("Finished slow function")
slow_function()
این دکوراتور قبل و بعد از اجرای تابع، زمان را اندازه میگیرد و مدت زمان اجرای آن را چاپ میکند.
نکات نسخههای جدید پایتون
در نسخههای جدید پایتون (مثلاً 3.9 به بعد)، دکوراتورها همچنان همان ساختار را دارند و تغییری در نحوه استفاده از آنها ایجاد نشده است. اما در ترکیب با type hint و قابلیتهای جدید مانند functools.cache یا functools.wraps امکانات بیشتری برای ساخت دکوراتورهای پیشرفته فراهم شده است.
خلاصه: دکوراتورها راهی برای اضافهکردن قابلیت به توابع موجود، بدون تغییر کد آنها هستند. با استفاده از آنها میتوانید رفتار توابع را تزئین، گسترش یا کنترل کنید، مثل اندازهگیری زمان اجرا، بررسی مجوزها، ثبت لاگ و غیره.