از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
دکوراتورها در پایتون چیست؟ با مثال کد توضیح داده شده است
سرفصلهای مطلب
در این آموزش، با دکوراتورهای پایتون آشنا می شوید: چه هستند، چگونه کار می کنند و چه زمانی از آنها استفاده کنید.
اما قبل از پرداختن به دکوراتورها، درک دو مفهوم اساسی در پایتون مفید است: توابع درجه یک و بسته شدن.
توابع درجه یک در پایتون
توابع درجه یک به این معنی است که با توابع در پایتون مانند هر شی دیگری رفتار می شود. این بدان معناست که توابع می توانند:
- به عنوان آرگومان به توابع دیگر منتقل می شود.
- از توابع دیگر برگشته است.
- به متغیرها اختصاص داده شده است.
درک بسته شدن
بسته شدن در پایتون به یک تابع اجازه می دهد تا محیطی که در آن ایجاد شده را به خاطر بسپارد. این بدان معناست که تابع داخلی حتی پس از اتمام اجرای تابع خارجی به متغیرهای موجود در محدوده محلی تابع خارجی دسترسی دارد.
بیایید به یک مثال برای درک بسته شدن نگاه کنیم:
def outer_func():
greet = "Hello!"
def inner_func():
print(greet)
return inner_func
newFunction = outer_func()
newFunction()
newFunction()
در این مثال:
- ما داریم
outer_func
که هیچ پارامتری را نمی گیرد. - داخل
outer_func
، یک متغیر محلی وجود داردgreet
. - یک
inner_func
درون تعریف شده استouter_func
که چاپ می کندgreet
. outer_func
برمی گرداندinner_func
.
وقتی زنگ میزنیم outer_func
، برمی گردد inner_func
اما بلافاصله آن را اجرا نمی کند. تابع برگشتی را به آن اختصاص می دهیم new_function
. اکنون، new_function
را می توان بعداً فراخوانی کرد و آن را به خاطر می آورد greet
متغیر از outer_func
دامنه، چاپ “سلام!” هر بار که تماس گرفته می شود.
این همان بسته شدن است – ما را به یاد می آورد greet
متغیر حتی پس از اتمام اجرای تابع خارجی.
روش تغییر بسته ها با پارامترها
اجازه دهید بسته شدن خود را با ارسال یک پارامتر به جای متغیر به the افزایش دهیم outer_func
:
def outer_func(greet):
def inner_func():
print(greet)
return inner_func
namasteFunc = outer_func("Namaste!")
howdyFunc = outer_func("Howdy!")
namasteFunc # Outputs: Namaste!
howdyFunc # Outputs: Howdy!
اینجا:
outer_func
حالا یک پارامتر می گیردgreet
.- این
inner_func
این را چاپ می کندgreet
. - وقتی زنگ میزنیم
outer_func
با “Namaste!” و “Howdy!”، عملکردهایی را برمی گرداند که این پیام های خاص را به خاطر می سپارند.
اگر می خواهید به عملکردهای درجه یک و بسته شدن عمیق بروید، می توانید این آموزش را اینجا بخوانید.
مقدمه ای بر دکوراتورهای پایتون
دکوراتور تابعی است که تابع دیگری را به عنوان آرگومان می گیرد، برخی از قابلیت ها را اضافه می کند و یک تابع جدید را برمی گرداند. این به شما این امکان را می دهد که تابع دیگری را برای گسترش رفتار آن (افزودن برخی عملکردها قبل یا بعد) بدون تغییر کد منبع تابع اصلی، “پیچ بندی” کنید.
بنابراین، این مثال پایانی است که در بالا استفاده کردیم:
def outer_func(greet):
def inner_func():
print(greet)
return inner_func
و این یک مثال دکوراتور است:
def decoratorFunction(func):
def wrapperFunction():
return func()
return wrapperFunction
در اینجا، به جای یک مقدار (مانند greet
، ما یک تابع را می پذیریم (func
) به عنوان استدلال. در داخل ما wrapperFunction
، به جای اینکه فقط یک پیام را چاپ کنیم، این را اجرا می کنیم func
و سپس آن را برگردانید.
روش اعمال دکوراتورها به توابع
def decoratorFunction(func):
def wrapperFunction():
return func()
return wrapperFunction
def display():
print('The display function was called')
decoratedDisplay = decoratorFunction(display)
decoratedDisplay() # Outputs: The display function was called
در این مثال:
- ما یک تابع ساده تعریف می کنیم
display
که پیامی را چاپ می کند. - ما اعمال می کنیم
decoratorFunction
بهdisplay
، ایجاد یک متغیر جدیدdecoratedDisplay
. - وقتی زنگ میزنیم
decoratedDisplay()
، آن را اجرا می کندwrapperFunction
داخل دکوراتور ما، که به نوبه خود زنگ می زند و برمی گرداندdisplay
تابع.
روش استفاده از @
نحو برای دکوراتورها
پایتون راه خواناتری برای اعمال دکوراتورها با استفاده از @
سمبل. درک این نحو سادهتر است و معمولاً در کد پایتون استفاده میشود:
def decoratorFunction(func):
def wrapperFunction():
print('Wrapper executed before {}'.format(func.__name__))
return func()
return wrapperFunction
@decoratorFunction
def display():
print('The display function was called')
display() # Outputs: Wrapper executed before display
# The display function was called
اینجا:
- ما استفاده می کنیم
@decoratorFunction
بالایdisplay
تعریف تابع این قند نحوی برایdisplay = decoratorFunction(display)
. - حالا وقتی زنگ میزنیم
display()
، به طور خودکار از طریق دکوراتور می رود و ابتدا پیام اضافی را چاپ می کند.
روش مدیریت توابع با آرگومان ها
اگر تابع اصلی ما آرگومانهایی داشته باشد، دکوراتوری که تاکنون نوشتهایم کار نخواهد کرد. برای مثال تابع زیر را در نظر بگیرید:
def display_info(name, age):
print('display_info was called with ({}, {})'.format(name, age))
display_info('Abdul Kalam', 83) # Outputs: display_info was called with (Abdul Kalam, 83)
اگر سعی کنیم دکوراتور فعلی خود را اعمال کنیم display_info
، یک خطا ایجاد می کند زیرا wrapperFunction
هیچ آرگومان نمی گیرد اما تابع اصلی دو آرگومان را انتظار دارد.
چگونه می توان دکوراتور را برای رسیدگی به استدلال ها تغییر داد
ما می توانیم دکوراتور خود را طوری تغییر دهیم که با استفاده از آن، هر تعداد آرگومان موقعیتی و کلیدواژه را بپذیرد *args
و **kwargs
.
def decoratorFunction(func):
def wrapperFunction(*args, **kwargs):
print('Wrapper executed before {}'.format(func.__name__))
return func(*args, **kwargs)
return wrapperFunction
@decoratorFunction
def display():
print('The display function was called')
@decoratorFunction
def display_info(name, age):
print('display_info was called with ({}, {})'.format(name, age))
display_info('Abdul Kalam', 83) # Outputs: Wrapper executed before display_info
# display_info was called with (Abdul Kalam, 83)
display() # Outputs: Wrapper executed before display
# The display function was called
در این دکوراتور به روز شده:
wrapperFunction
اکنون هر تعداد موقعیت (*args
) و آرگومان های کلمه کلیدی (**kwargs
).- این استدلال ها به
func
هنگامی که آن را در داخل نامیده می شودwrapperFunction
. - این تنظیم باعث می شود دکوراتور ما به اندازه کافی انعطاف پذیر باشد تا بتواند هر عملکردی را بدون توجه به پارامترهای آن انجام دهد.
روش استفاده از کلاس ها به عنوان دکوراتور
در پایتون نیز می توانید از کلاس ها برای ایجاد دکوراتورها استفاده کنید. این رویکرد انعطاف پذیری بیشتری را ارائه می دهد و می تواند برای دکوراتورهای پیچیده خواناتر باشد.
در اینجا روش تبدیل یک دکوراتور مبتنی بر عملکرد به یک دکوراتور کلاس محور آورده شده است:
ابتدا با دکوراتور مبتنی بر عملکرد اصلی شروع می کنیم:
def decoratorFunction(func):
def wrapperFunction(*args, **kwargs):
print('Wrapper executed before calling {}'.format(func.__name__))
return func(*args, **kwargs)
return wrapperFunction
بعد، کلاسی ایجاد می کنیم که این عملکرد را تقلید می کند:
مرحله 1: کلاس را تعریف کنید
یک کلاس جدید به نام تعریف می کنیم DecoratorClass
. این کلاس به دکوراسیون رسیدگی خواهد کرد process.
class DecoratorClass:
مرحله 2: __init__
روش
این __init__
متد یک متد خاص در کلاس های پایتون است. زمانی فراخوانی می شود که یک نمونه (ابجکت) از کلاس ایجاد شود. این روش شی را مقداردهی اولیه می کند.
- عبور می کنیم
func
به عنوان یک استدلال برای__init__
روش. - درون
__init__
روش، ما ذخیره می کنیمfunc
در یک متغیر نمونهself.func
.
class DecoratorClass:
def __init__(self, func):
self.func = func
مرحله 3: __call__
روش
این __call__
روش یک روش خاص دیگر است. این اجازه می دهد تا یک نمونه از کلاس به عنوان یک تابع فراخوانی شود.
- این
__call__
روش می گیرد*args
و**kwargs
برای رسیدگی به هر تعداد آرگومان موقعیتی و کلید واژه. - داخل
__call__
، ما print یک پیام و سپس تابع اصلی را با آرگومان های آن فراخوانی کنید.
class DecoratorClass:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('Executing wrapper before {}'.format(self.func.__name__))
return self.func(*args, **kwargs)
با استفاده از دکوراتور کلاس محور
سپس از @
نحو برای اعمال دکوراتور مبتنی بر کلاس به توابع، درست مانند کاری که با دکوراتور مبتنی بر تابع انجام دادیم.
@DecoratorClass
def display():
print('display function executed')
@DecoratorClass
def display_info(name, age):
print('display_info function executed with arguments ({}, {})'.format(name, age))
اجرای توابع تزئین شده
وقتی توابع تزئین شده را فراخوانی می کنیم __call__
روش از DecoratorClass
اجرا می شود:
display_info('Abdul Kalam', 83)
display()
در اینجا مثال کاملی از دکوراتورهای کلاسی آورده شده است:
class DecoratorClass:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('Executing wrapper before {}'.format(self.func.__name__))
return self.func(*args, **kwargs)
@DecoratorClass
def display():
print('display function executed')
@DecoratorClass
def display_info(name, age):
print('display_info function executed with arguments ({}, {})'.format(name, age))
display_info('Abdul Kalam', 83)
display()
در این دکوراتور کلاس محور:
- این
__init__
متد تابع اصلی را به نمونه ای از کلاس پیوند می دهد. - این
__call__
روش اجازه می دهد تا یک نمونه ازDecoratorClass
به عنوان یک تابع فراخوانی شود. پیامی را چاپ می کند و تابع اصلی را با هر آرگومان فراخوانی می کند. - تزئین می کنیم
display
وdisplay_info
با@DecoratorClass
. - چه زمانی
display_info('Abdul Kalam', 83)
نامیده می شود، آن را اجرا می کند__call__
روش ازDecoratorClass
، پیام را چاپ می کند و سپس اجرا می کندdisplay_info
. - چه زمانی
display()
نامیده می شود، آن را اجرا می کند__call__
روش ازDecoratorClass
، پیام را چاپ می کند و سپس اجرا می کندdisplay
.
هر دو دکوراتور مبتنی بر عملکرد و کلاس مبتنی بر عملکرد یکسانی را ارائه می دهند. انتخاب بین آنها بستگی دارد روی ترجیح شخصی و پیچیدگی منطق دکوراتور.
نتیجه
دکوراتورها در پایتون راهی تمیز و قدرتمند برای گسترش رفتار توابع ارائه می دهند. با درک عملکردهای درجه یک و بسته شدن، می توانید روش عملکرد دکوراتورها را در زیر کاپوت درک کنید.
چه از دکوراتورهای مبتنی بر عملکرد یا کلاسمحور استفاده میکنید، میتوانید عملکردهای خود را بدون تغییر کد اصلی آنها ارتقا دهید و پایه کد خود را تمیز و قابل نگهداری نگه دارید.
- دکوراتورها برای گسترش عملکرد عملکردها قدرتمند هستند.
- آنها را می توان با استفاده از توابع یا کلاس ها پیاده سازی کرد.
- این
@decorator
نحو روشی تمیزتر و خواناتر برای اعمال تزئینات است. - آنها با انتزاع کردن عملکردهای رایج به حفظ کد شما کمک می کنند تا DRY (خودتان را تکرار نکنید).
منتشر شده در 1403-06-19 02:49:07