از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
مقدمه ای بر دکوراتورهای پایتون
سرفصلهای مطلب
معرفی
در پایتون، دکوراتور یک الگوی طراحی است که میتوانیم از آن برای افزودن قابلیتهای جدید به یک شیء موجود بدون نیاز به تغییر ساختار آن استفاده کنیم. یک دکوراتور باید مستقیماً قبل از عملکردی که قرار است گسترش یابد فراخوانی شود. با دکوراتورها، می توانید عملکرد یک متد، یک تابع یا یک کلاس را به صورت پویا و بدون استفاده مستقیم از کلاس های فرعی تغییر دهید. این ایده خوبی است زمانی که می خواهید عملکرد تابعی را که نمی خواهید مستقیماً تغییر دهید، گسترش دهید. الگوهای دکوراتور را می توان در همه جا پیاده سازی کرد، اما پایتون سینتکس و ویژگی های گویاتری را برای آن ارائه می دهد.
در این مقاله به طور مفصل به دکوراتورهای پایتون می پردازیم.
روش ایجاد دکوراتور
بیایید ببینیم چگونه می توان دکوراتورها را در پایتون ایجاد کرد. به عنوان مثال، ما یک دکوراتور ایجاد می کنیم که می توانیم از آن برای تبدیل رشته خروجی یک تابع به حروف کوچک استفاده کنیم. برای این کار باید یک تابع دکوراتور ایجاد کنیم و باید یک لفاف داخل آن تعریف کنیم. به اسکریپت زیر نگاه کنید:
def lowercase(func):
def wrapper():
func_ret = func()
change_to_lowercase = func_ret.lower()
return change_to_lowercase
return wrapper
در اسکریپت بالا، ما به سادگی یک دکوراتور به نام ایجاد کرده ایم lowercase
که یک تابع را به عنوان آرگومان خود می گیرد. برای امتحان کردن ما lowercase
تابع باید یک تابع جدید ایجاد کنیم و سپس آن را به این دکوراتور منتقل کنیم. توجه داشته باشید که از آنجایی که توابع در پایتون درجه یک هستند، می توانید تابع را به یک متغیر اختصاص دهید یا آن را به عنوان یکی در نظر بگیرید. ما از این ترفند برای فراخوانی تابع دکوراتور استفاده می کنیم:
def hello_function():
return 'HELLO WORLD'
decorate = lowercase(hello_function)
print(decorate())
خروجی
hello world
توجه داشته باشید که می توانید دو کد بالا را در یک کد ادغام کنید. ما تابع را ایجاد کردیم hello_function()
که جمله “HELLO WORLD” را برمی گرداند. سپس دکوراتور را فراخوانی کردیم و نام این تابع را به عنوان آرگومان در حالی که آن را به متغیر «decorate» اختصاص دادیم، ارسال کردیم. پس از اجرا، می توانید ببینید که جمله به دست آمده به حروف کوچک تبدیل شده است.
با این حال، راه سادهتری برای استفاده از دکوراتورها در پایتون وجود دارد. ما به سادگی می توانیم اضافه کنیم @
نماد قبل از نام تابع دکوراتور درست بالای تابعی که باید تزئین شود. مثلا:
@lowercase
def hello_function():
return 'HELLO WORLD'
print(hello_function())
خروجی
hello world
روش اعمال دکوراتورهای متعدد برای یک تابع
پایتون به ما اجازه می دهد تا بیش از یک دکوراتور را برای یک تابع اعمال کنیم. برای انجام صحیح این کار، مطمئن شوید که دکوراتورها را به همان ترتیبی که آنها را به عنوان کد معمولی اجرا می کنید، اعمال کنید. به عنوان مثال، دکوراتور زیر را در نظر بگیرید:
def split_sentence(func):
def wrapper():
func_ret = func()
output = func_ret.split()
return output
return wrapper
در اینجا ما یک دکوراتور ایجاد کرده ایم که یک جمله ورودی را می گیرد و آن را به قسمت های مختلف تقسیم می کند. نام دکوراتور داده شده است split_sentence
. حالا بیایید درخواست کنیم lowercase
و split_sentence
تزئینات به یک عملکرد.
برای اجرای این عملیات به ترتیب صحیح، آنها را به صورت زیر اعمال کنید:
@split_sentence
@lowercase
def hello_function():
return 'HELLO WORLD'
print(hello_function())
خروجی
('hello', 'world')
جمله ما از زمانی که هر دو را اعمال کردیم به دو قسمت تقسیم شده و به حروف کوچک تبدیل شده است lowercase
و split_sentence
تزئینات به hello_function
.
انتقال استدلال به توابع دکوراتور
دکوراتورهای پایتون همچنین می توانند آرگومان هایی که به توابع تزئین شده ارسال می شوند را رهگیری کنند. آرگومان ها به نوبه خود در زمان اجرا به تابع تزئین شده ارسال می شوند. به مثال زیر توجه کنید:
def my_decorator(func):
def my_wrapper(argument1, argument2):
print("The arguments are: {0}, {1}".format(argument1, argument2))
func(argument1, argument2)
return my_wrapper
@my_decorator
def names(firstName, secondName):
print("Your first and second names are {0} and {1} respectively".format(firstName, secondName))
print(names("Nicholas", "Samuel"))
خروجی
The arguments are: Nicholas, Samuel
Your first and second names are Nicholas and Samuel respectively
در اسکریپت بالا، دکوراتور دو استدلال را می پذیرد: argument1
و argument1
.
ایجاد دکوراتورهای همه منظوره
دکوراتورهای عمومی را می توان برای هر عملکردی اعمال کرد. به عنوان مثال، این نوع دکوراتورها برای اهداف رفع اشکال بسیار مفید هستند.
ما می توانیم آنها را با استفاده از args
و **kwargs
استدلال ها تمام آرگومان های موقعیتی و کلیدواژه به ترتیب در این دو متغیر ذخیره می شوند. با args
و kwargs
، می توانیم هر تعداد آرگومان را در طول فراخوانی تابع ارسال کنیم. مثلا:
def my_decorator(func):
def my_wrapper(*args, **kwargs):
print('Positional arguments:', args)
print('Keyword arguments:', kwargs)
func(*args)
return my_wrapper
@my_decorator
def function_without_arguments():
print("No arguments")
function_without_arguments()
خروجی
Positional arguments: ()
Keyword arguments: {}
No arguments
همانطور که می بینید، هیچ استدلالی به دکوراتور منتقل نشد.
حال بیایید ببینیم چگونه می توانیم مقادیر را به آرگومان های موقعیتی منتقل کنیم:
@my_decorator
def function_with_arguments(x, y, z):
print(x, y, z)
function_with_arguments(5, 15, 25)
خروجی
Positional arguments: (5, 15, 25)
Keyword arguments: {}
5 15 25
ما سه استدلال موضعی را به دکوراتور منتقل کرده ایم. برای ارسال آرگومان های کلمه کلیدی، باید از کلمات کلیدی در فراخوانی تابع استفاده کنیم. به عنوان مثال:
@my_decorator
def passing_keyword_arguments():
print("Passing keyword arguments")
passing_keyword_arguments(firstName="Nicholas", secondName="Samuel")
خروجی
Positional arguments: ()
Keyword arguments: {'secondName': 'Samuel', 'firstName': 'Nicholas'}
Passing keyword arguments
دو آرگومان کلیدواژه به دکوراتور منتقل شد.
در بخش بعدی به روش رفع اشکال دکوراتورها می پردازیم.
روش اشکال زدایی دکوراتورها
در این مرحله، حتماً دیده اید که ما از دکوراتورها برای پیچیدن کارکردها استفاده می کنیم. بسته شدن wrapper نام تابع اصلی، لیست پارامترهای آن و رشته docstring را پنهان می کند.
به عنوان مثال: اگر سعی کنیم متادیتا را برای دکوراتور بدست آوریم function_with_arguments
، فراداده بسته شدن wrapper را دریافت خواهیم کرد. اجازه دهید این را نشان دهیم:
function_with_arguments.__name__
خروجی
'my_wrapper'
این یک چالش بزرگ در هنگام اشکال زدایی است. با این حال، پایتون فراهم می کند functools.wraps
دکوراتور که می تواند در حل این چالش کمک کند. با کپی کردن ابرداده از دست رفته در بسته بندی تزئین شده شما کار می کند.
حالا اجازه دهید نشان دهیم که چگونه این کار می کند:
import functools
def lowercase(func):
@functools.wraps(func)
def my_wrapper():
return func().lower()
return my_wrapper
@lowercase
def hello_function():
"Saying hello"
return 'HELLO WORLD'
print(hello_function())
خروجی
hello world
از آنجایی که استفاده کردیم functools.wraps
روی تابع wrapper، میتوانیم فراداده تابع را برای “hello_function” بررسی کنیم:
hello_function.__name__
خروجی
'hello_function'
hello_function.__doc__
خروجی
'Saying hello'
اسکریپت بالا به وضوح نشان می دهد که فراداده اکنون به تابع اشاره دارد تا به wrapper. توصیه میکنم همیشه استفاده کنید functools.wraps
هر زمانی که در حال تعریف دکوراتور هستید. این کار اشکال زدایی را برای شما بسیار آسان تر می کند.
نتیجه
هدف دکوراتورها تغییر عملکرد یک کلاس، متد یا تابع به صورت پویا بدون استفاده مستقیم از کلاس های فرعی یا تغییر کد منبع کلاس، متد یا تابعی است که باید تزئین کنیم. در این مقاله روش ایجاد دکوراتورهای ساده و عمومی و روش انتقال استدلال به دکوراتورها را دیدیم. همچنین روش اشکال زدایی دکوراتورها را در حین توسعه با استفاده از آن دیدیم functools
مدول.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-24 10:49:05