ویدیو آموزش حرفه‌ای دکوراتورها در پایتون

August 2019

پیش نیازها:

ویدیو آشنایی عمیق با function در پایتون

ویدیو آشنایی با args و kwargs در پایتون

 

decorator پایتون چیست؟

یک دکوریتور در پایتون یک فانکشن است که فانکشن دیگری را به عنوان آرگومان خود می گیرد و یک تابع دیگر را برمی گرداند. دکوراتورها می توانند بسیار مفید باشند زیرا اجازه می دهند عملکرد یک فانکشن موجود گسترش یابد، بدون هیچ گونه تغییری در کد اصلی فانکشن.

 

دکوراتورها به احتمال زیاد به زیباترین و قدرتمندترین امکانات طراحی در پایتون تعلق دارند، اما در عین حال، بسیاری آنها را پیچیده می دانند. به طور دقیق، استفاده از دکوراتورها بسیار آسان است، اما نوشتن دکوراتورها می تواند پیچیده باشد، به خصوص اگر با دکوراتورها و برخی از مفاهیم برنامه نویسی کاربردی تجربه ندارید.

 

decorator مانند "بسته بندی" توابع یا کلاسهایی است که ما برای افزودن رفتارهای بیشتر آنها بدون تغییر آنها استفاده می کنیم. برای موارد زیر مفید است:

1. برخی از رفتارها را به توابع/کلاسهای داخلی یا شخص ثالث اضافه کنید ، بنابراین نیازی به فورک و تغییر کد منبع نداریم.

2. از این رفتارهای سفارشی در چندین عملکرد/کلاس استفاده کنید.

 

در این آموزش درباره دکوراتورها، اینکه چه چیزی هستند و نحوه ایجاد و استفاده از آنها را بررسی می کنیم. دکوراتور یک نحو ساده برای فراخوانی توابع مرتبه بالاتر ارائه می دهند. decorator تابعی است که عملکرد دیگری را انجام می دهد و رفتار تابع دوم را بدون تغییر صریح آن گسترش می دهد. گیج کننده به نظر می رسد، اما واقعاً اینطور نیست، مخصوصاً بعد از اینکه چند نمونه از نحوه عملکرد دکوراتورها را مشاهده کردید.


 

ساخت دکوراتور پایتون

همانطور که در مقدمه بیان کردم ، یک decorator پایتون مانند یک بسته بندی یک تابع یا یک کلاس است. هنوز خیلی مفهومی است بیایید چند کد را به شرح زیر بررسی کنیم:

def function_decorator(func):
    def wrapped_func():
        # Do something before the function is executed
        func()
        # Do something after the function has been executed
    return wrapped_func

 

کد بالا تعریف دکوراتور است که فانکشنی را تزئین می کند.

 

 

در تابع داخلی wrapped_func، ما می توانیم هر کاری را قبل و بعد از فراخوانی func انجام دهیم. پس از تعریف دکوراتور، ما به سادگی از آن به صورت زیر استفاده می کنیم.

@function_decorator
def func():
    pass

سپس، هرگاه تابع func را صدا بزنیم، رفتارهایی که در دکوراتور تعریف کرده ایم نیز اجرا می شود.


 

مثالی از یک تابع تو در تو(decorator)

می دانم ، هیچ کس فقط مفاهیم را دوست ندارد. در اینجا یک مثال ساده از تابع تو در تو یا decorator پایتون است.

def function_decorator(func):
    def wrapped_func():
        print('=' * 30)
        func()
        print('=' * 30)
    return wrapped_func

 

حالا از این دکوریتور استفاده میکنیم:

@function_decorator
def test():
    print('Hello World!')

 

و نتیجه:

test()

==============================
Hello World!
==============================

 

در این تابع تودرتو، 30 علامت مساوی "=" را قبل و بعد از اجرای تابع خروجی می دهیم. بنابراین، می توانیم بگوییم که دکوراتور برای افزودن ردیف بالا و پایین = برای هرگونه فانکشنی که چیزی را چاپ می کند استفاده می شود.


 

ارسال آرگومان به دکوراتور پایتون

اگر بخواهیم برخی از توابع را که انتظار آرگومان دارند تزئین کنیم، چه کنیم؟ به عنوان مثال، فانکشن زیر یک نام گرفته و یک سلام ارسال میکند.

@function_decorator
def greeting(name):
    print(f'Hey {name}! Good Morning!')

 

بیایید همان دکوراتوری را که در قسمت بالا تعریف شده است، امتحان کنیم.

>>> greeting('amir')

Traceback (most recent call last):
  File "/home/amir/Desktop/python/one.py", line 13, in <module>
    greeting('amir')
TypeError: wrapped_func() takes 0 positional arguments but 1 was given

 

ما نمی توانیم این کار را انجام دهیم، زیرا decorator ما انتظار هیچ گونه آرگومانی را ندارد. البته، پایتون یک راه حل آسان برای این مشکل ارائه داد. بیایید دوباره دکوراتور را تعریف کنیم.

def function_decorator(func):
    def wrapped_func(*args, **kwargs):
        print('=' * 30)
        func(*args, **kwargs)
        print('=' * 30)
    return wrapped_func

 

تنها تفاوت این است که ما *args ، ** kwargs را به عنوان آرگومان به تابع داخلی اضافه کرده و آنها را به تابع منتقل می کنیم. این اطمینان می دهد که هرگونه آرگومان به سادگی وارد می شود، بنابراین هیچ مشکلی ایجاد نمی شود.

>>> greeting('amir')

==============================
Hey amir! Good Morning!
==============================

 

مثال‌های بیشتر از دکوراتورهای پایتون

بگذارید فقط یک مثال دیگر بزنم. مطمئناً ما می توانیم چیزی فراتر از مثال‌های بالا داشته باشیم. ما می توانیم از دکوراتورها به هر روشی که دوست داریم استفاده کنیم. به عنوان مثال، ما می خواهیم یک دکوراتور تعریف کنیم که تاریخ و زمان را قبل از logging اضافه می کند.

from datetime import datetimedef timed_log(log_msg):
    def time_added(*args, **kwargs):
        return f'[{datetime.now()}] {log_msg(*args, **kwargs)}'
    return time_added

 

در تعریف بالا، تابع تزئین شده ابتدا باید چیزی را خروجی دهد، اما اکنون دکوراتور ما تاریخ-زمان را قبل از آن اضافه می کند.

 

فرض کنید ما دو تابع log مختلف داریم ، یکی یک عدد صحیح را به عنوان "شماره خط" در نظر می گیرد و به کاربران نشان می دهد که خطایی در آنجا رخ داده است، و دیگری به سادگی به کاربر می گوید که همه چیز با موفقیت انجام شده است.

@timed_log
def log_error(line_no):
    return f'There is an error happend at line {line_no}'

@timed_log
def log_done():
    return 'Great! All processed done.'

 

لطفاً توجه داشته باشید که دکوراتور برای هر دو عملکرد مورد استفاده مجدد قرار گرفته است.

>>> print(log_error(50))
>>> print(log_done())

[2021-09-16 17:02:08.923413] There is an error happend at line 50
[2021-09-16 17:02:08.923530] Great! All processed done.

 

اگر ویدیو بالا را دوست داشتید، پیشنهاد میکنیم به مطالب زیر هم سر بزنید:

توضیح دکوراتور porperty در پایتون

آموزش دکوراتورهای http جنگو

دوره های آموزش پروژه محور و پیشرفته پایتون

آموزش شی گرایی در پایتون - توضیح دکوراتورهای class method و static method

ارسال نظر

تلاش میکنم سوالات شما را در کمتر از یک روز پاسخ بدم

alirezai

January 2022

خدایی دمت گرم ادامه بده همینطور

پاسخ به نظر


Mahdi

November 2021

سلام امیر
خدایی قسمت 5 رو چیکارش کردی؟
ما اگر بخوایم آرگومان از طریق دکوریتور بگیریم، باید یدونه فانکشن بالا تر از همه بنویسیم و بعد برای گرفتن خود فانکشن مفعول، از اولین فانکشن درونی دکوریتور استفاده شد و بعد برای گرفتن آرگومان های ارسالی به فانشکن مفعول، یدونه فانکشن درون فانکشن قبلی مینویسیم.
الان طبق چه منطقی اینطوری پشد؟!
قضیه چیه؟

پاسخ به نظر


Ali Ghane

November 2020

سلام امیرجان.

حرف نداری.
از طریق یکی از دوستام با سایت بسیار خوبت آشنا شدم و واقعا خوشحالم از آشنا شدن باهات...
تدریس بی تکلفت و خودمونیت حرف نداره.
بینهایت درود و احترام و انرژی مثبت بهت که نیتت خیره و تجربیات و دانسته هاتا در اختیار بقیه قرار میدی.
امیدوارم همیشه سالم و موفق باشی، احساس خوشبحتی کنی، خدا خودت و عزیزانتا حفظ کنه و همه آرزو های خوب دیگه
خیلی آقایی، دمت گرم.

پاسخ به نظر


امیرحسین بیگدلو

November 2020

سلام
خیلی ممنونم ازت
همه ما وظیفه داریم تا حد امکان به بقیه کمک کنیم.


مهدی

May 2022

خیلی خیلی ممنون از امیر آقای عزیز