Decorators در پایتون
در این مقاله نگاهی به decoratorها و نحوه ایجاد و استفاده از آنها میپردازیم.
decoratorها دستورالعمل سادهای برای فراخوانی توابع مرتبه بالا را برای ما فراهم میکنند. به عبارت دیگر decorator تابعی است، که تابع دیگر را دریافت میکند و رفتار آن را تغییر میدهد (بدون آن که ماهیت خودِ تابع تغییر کند) و آن را برمیگرداند.
توابع
قبل از اینکه به مفهوم decorator بپردازیم، ابتدا باید بدانید که توابع چگونه کار میکنند. اساسا توابع مقداری را بر اساس یک سری آرگومان برمیگردانند.
def func(value): return value+1 print(func(5))
در پایتون، توابع first-class objects هستند. بدین معنی که توابع میتوانند به عنوان آرگومان به توابع دیگر فرستاده و یا در متغیری ذخیره شوند.
def func(value): return value+1 def func_in_func(function, num): return func(num) print(func_in_func(func,5)) func_in_variable = func_in_func print(func_in_variable(func,7))
با اجرای کد بالا خروجی ۶ و ۸ را به ما میدهد.
توابع تودرتو
شما در پایتون قابلیت این را دارید که در داخل توابع، توابع دیگری را تعریف کنید که به توابع تودرتو معروفاند.
def parent_func(): print("Printing from parent function.") def first_child(): return "Printing from first child" def second_child(): return "Printing from second child" print(first_child()) print(second_child()) parent_func()
که خروجی زیر را تولید میکند:
Printing from parent function. Printing from first child Printing from second child
شما میتوانید فقط در داخل تابع parent، توابع first child و second child را فراخوانی کنید. فراخوانی خارج از تابع parent، به شما NameError خواهد داد.
برگرداندن تابع
پایتون به شما این قابلیت را میدهد که توابع، توابع را برگردانند. برای مثال، در کد زیر اگر عدد فرستاده شده به تابع ۱۰ نباشد، تابع second child فرستاده میشود. در غیر این صورت تابع first child فرستاده میشود.
def parent(num): def first_child(): return "Printing from the first_child() function." def second_child(): return "Printing from the second_child() function." try: assert num == 10 return first_child except AssertionError: return second_child foo = parent(10) bar = parent(11) print(foo) print(bar) print(foo()) print(bar())
و خروجی به صورت زیر میشود:
<function parent.<locals>.first_child at 0x0000021DC45FDEA0> <function parent.<locals>.second_child at 0x0000021DC46192F0> Printing from the first_child() function. Printing from the second_child() function.
Decorators
به مثال زیر توجه کنید:
def my_decorator(some_function): def wrapper(): print("ZeroToHero can teach you everything.") some_function() print("ZeroToHero can teach you everything.") return wrapper def just_some_function(): print("EVERYTHING!!!!") just_some_function = my_decorator(just_some_function) just_some_function()
میتوانید حدس بزنید که خروجی چه خواهد شد؟
ZeroToHero can teach you anything. ANYTHING!!!! ZeroToHero can teach you anything.
در اینجا به تابعی، تابع دیگر را به عنوان آرگومان دادیم و بعد از گسترش رفتارِ آن، در متغیری ذخیره و در آخر هم با آن متغیر، تابع جدید خود را فراخوانی کردیم. تمام این کارها بدون تغییر ماهیتِ اصلیِ خودِ تابع انجام شد.
پایتون به شما این امکان را میدهد که این روند را به صورت سادهتر استفاده نمایید.
برای مثال میتوان کد بالا را به صورت ساده شده، به این حالت بنویسیم.
def my_decorator(some_function): def wrapper(): print("ZeroToHero can teach you everything.") some_function() print("ZeroToHero can teach you everything.") return wrapper @my_decorator def just_some_function(): print("EVERYTHING!!!!") just_some_function()
برای کار با decorator از کاراکتر @ استفاده میکنیم. تابعی که در خط بعد از @ بیاید، به عنوان آرگومان به تابعی که در کنار علامت @ تعریف شده، فرستاده و در آن تغییراتی ایجاد میشود. در نظر داشته باشید که در هنگام فراخوانیِ تابع، تغییرات را مشاهده خواهید کرد. به صورت سادهتر my_decorator@ همان کار just_some_function = my_decorator(just_some_function) را انجام میدهد.
نمونههای استفاده شده از Decorator
در قطعه کد زیر decorator به شما کمک میکند که زمان اجرای توابع را محاسبه کنید.
import time def timing_function(some_function): def wrapper(): t1 = time.time() some_function() t2 = time.time() return "Time it took to run the function: " + str((t2 - t1)) + " seconds" return wrapper @timing_function def my_function(): num_list = [] for num in (range(0, 10**7)): num_list.append(num) @timing_function def my_function_1(): num_list = [num for num in range(0, 10**7)] print(my_function()) print(my_function_1())
استفاده از decorator در مواقعی که بخواهیم یک عملی را روی توابع زیادی اعمال کنیم، کاربرد زیادی دارد. یکی از پر استفادهترین کاربردهای decorator، استفاده از آن در ()login_requiredها است، که به ما تضمین میدهد که کاربر در وبسایت ما درست وارد شده است.
مطالب زیر را حتما مطالعه کنید
آشنایی با توابع در پایتون
راه اندازی Django به همراه Postgresql، Nginx و Gunicorn
آشنایی با حلقه ها در پایتون
آشنایی با رشته در پایتون
برنامه نویسی چند نخی در پایتون
تولید اعداد Random با Python
2 Comments
Join the discussion and tell us your opinion.
دیدگاهتان را بنویسید لغو پاسخ
برای نوشتن دیدگاه باید وارد بشوید.
بسیار عالی و زیبا توضیح دادین ….
مدت زیادی بود که با مفهوم دکوراتور ها مشکل داشتم که الان کاملا متوجه شدم …
سپاس 🙂
آموزش خیلی روان و کامل
دمتون گرم