ویدیو آموزش حرفهای دکوراتورها در پایتون
پیش نیازها:
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
کد بالا تعریف دکوراتور است که فانکشنی را تزئین می کند.
- function_decorator نام دکوراتور است.
- wrapped_func نام فانکشن داخلی است که فقط در همین دکوراتور استفاده میشود.
- 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 در پایتون
دوره های آموزش پروژه محور و پیشرفته پایتون
آموزش شی گرایی در پایتون - توضیح دکوراتورهای class method و static method
ارسال نظر