به آموزشگاه مجازی سینا خوش آمدید!

آموزش دکوراتور(decorator) در پایتون

امتیاز
(0)

دکوراتور‌ها(decorator) در پایتون، به ما امکان می‌دهند تا یک رفتار اضافی را به یک تابع اضافه کنیم، بدون اینکه کدهای آن تابع را تغییر دهیم. دکوراتور یک تابع است که یک تابع دیگر را بعنوان ورودی(input)، دریافت می‌کند و یک تابع جدید را برمی‌گردانَد(return می‌کند).


ایجاد یک دکوراتور ساده

ابتدا دکوراتور را تعریف کنید، سپس دستور @decorator_name را در بالای تابع اعطا شده قرار دهید. دقت کنید که در دستور مذکور، باید به جای عبارت decorator_name پس از @، نام تابع دکوراتور را قرار دهید. 

مثال شماره 1

یک تابع دکوراتور ساده که باعث می‌شود مقدار برگشتیِ تابع اعطا شده(decorated) به حروف بزرگ تبدیل شوند:

def changecase(func):
  def myinner():
    return func().upper()
  return myinner

@changecase
def myfunction():
  return "Hello Sally"

print(myfunction())

نتیجه:

HELLO SALLY
امتحان کنید

با قرار دادن دستور @changecase در بالای تابع myfunction()، این تابع به صورت پارامتر، به تابع changecase اعطا می‌شود. به تابع changecase تابع دکوراتور گفته می‌شود؛ زیرا دیگر تابع ها، به آن اعطا می‌شوند. و به تابع myfunction تابع اعطا شده(decorated) گفته می‌شود. 


فراخوانی چندباره‌ی دکوراتور

ما می‌توانیم یک تابع دکوراتور را چندین بار فراخوانی کنیم. تنها کافیست نام دکوراتور را به همراه @ در بالای تابعی که می‌خواهیم اعطا شود، قرار دهیم. 

مثال شماره 2

استفاده از دکوراتور @changecase در دو تابع:

def changecase(func):
  def myinner():
    return func().upper()
  return myinner

@changecase
def myfunction():
  return "Hello Sally"

@changecase
def otherfunction():
  return "I am speed!"

print(myfunction())
print(otherfunction())

نتیجه:

HELLO SALLY
I AM SPEED!
امتحان کنید

استفاده از آرگومان‌ها در تابع اعطاشده(Decorated)

ما می‌توانیم تابع‌هایی که نیاز به آرگومان دارند را نیز بعنوان تابع ‌های اعطا شده مورد استفاده قرار دهیم؛ فقط مطمئن شوید که این آرگومان‌ها را در تابع wrapper پاس دهید:

مثال شماره 3

تابع‌هایی که آرگومان دارند نیز می‌توانند به دکوراتور اعطا شوند:

def changecase(func):
  def myinner(x):
    return func(x).upper()
  return myinner

@changecase
def myfunction(nam):
  return "Hello " + nam

print(myfunction("John"))

نتیجه:

HELLO JOHN
امتحان کنید

دستورات *args و **kwargs

گاهی اوقات، تابع دکوراتور، کنترلی روی آرگومان‌هایی که از تابع اعطا شده(decorated) پاس داده شده‌اند ندارد، برای حل این مشکل، دستورِ (*args, **kwargs) را در تابع wrapper (یعنی تابعی که در درون تابع دکوراتور قرار دارد) اضافه کنید؛ به این طریق، تابع wrapper می‌تواند هر تعداد و هر نوع آرگومانی را بپذیرد؛ و آنها را به تابع اعطا شده پاس دهد. برای اطلاعات بیشتر در مورد این دو آرگومان، اینجا کلیک کنید

مثال شماره 4

ایمن کردن تابع با استفاده از آرگومان‌های *args و **kwargs:

def changecase(func):
  def myinner(*args, **kwargs):
    return func(*args, **kwargs).upper()
  return myinner

@changecase
def myfunction(nam):
  return "Hello " + nam

print(myfunction("John"))

نتیجه:

HELLO JOHN
امتحان کنید

استفاده از آرگومان برای دکوراتور(Decorator)

ما می‌توانیم با اضافه کردن یک سطحِ wrapper دیگر، برای خودِ دکوراتورها، آرگومان اختصاص دهیم:

مثال شماره 5

یک سازنده‌ی دکوراتور که یک آرگومان را می‌پذیرد و بسته به مقدار این آرگومان، انتخاب را تغییر می‌دهد:

def changecase(n):
  def changecase(func):
    def myinner():
      if n == 1:
        a = func().lower()
      else:
        a = func().upper()
      return a
    return myinner
  return changecase

@changecase(1)
def myfunction():
  return "Hello Linus"

print(myfunction())

نتیجه:

hello linus
امتحان کنید

استفاده از چندین دکوراتور(Multiple Decorators)

ما می‌توانیم از چندین دکوراتور روی یک تابع ( اعطا شده) استفاده کنیم. برای انجام این کار، فراخوانی‌های دکوراتور را روی یکدیگر در بالای تابع اعطا شده قرار دهید. دکوراتورها به ترتیب معکوس فراخوانی می‌شوند؛ و این کار از نزدیک‌ترین مورد به تابع اعطا شده، شروع می‌شود. 

مثال شماره 6

یک دکوراتور برای تبدیل به حروف بزرگ و یک دکوراتور هم برای اضافه کردن یک خوش‌آمد گویی:

def changecase(func):
  def myinner():
    return func().upper()
  return myinner

def addgreeting(func):
  def myinner():
    return "Hello " + func() + " Have a good day!"
  return myinner

@changecase
@addgreeting
def myfunction():
  return "Tobias"

print(myfunction())

نتیجه:

HELLO TOBIAS HAVE A GOOD DAY!
امتحان کنید

حفاظت از داده‌های متای تابع

تابع‌ها در پایتون یک سری داده‌های متا(metadata) دارند که می‌توانیم با استفاده از خصوصیت های __name__  و  __doc__ به آنها دسترسی پیدا کنیم. 

مثال شماره 7

در حالت عادی، می‌توانیم با استفاده از خصوصیت __name__ نام یک تابع را برگردانیم(return کنیم):

def myfunction():
  return "Have a great day!"

print(myfunction.__name__)

نتیجه:

myfunction
امتحان کنید

اما وقتی که یک تابع اعطا(decorated) می‌شود، داده‌های متای تابع اصلی گم(lost) می‌شوند. 

مثال شماره 8

سعی کنید نام یک تابع اعطا شده(decorated) را برگردانید؛ اما نتیجه‌ی درستی به دست نخواهد آمد:

def changecase(func):
  def myinner():
    return func().upper()
  return myinner

@changecase
def myfunction():
  return "Have a great day!"

print(myfunction.__name__)

نتیجه:

myinner
امتحان کنید

برای حل این مشکل، پایتون یک تابع داخلی(built-in) به نام functools.wraps دارد که می‌توانیم از آن برای حفاظت کردن از نام و داک‌استرینگ(docstring) تابع اصلی استفاده کنیم. 

مثال شماره 9

ایمپورت کردن functools.wraps برای حفاظت از نام و داک‌استرینگ(docstring) تابع اصلی:

import functools

def changecase(func):
  @functools.wraps(func)
  def myinner():
    return func().upper()
  return myinner

@changecase
def myfunction():
  return "Have a great day!"

print(myfunction.__name__)

نتیجه:

myfunction
امتحان کنید

 


منبع: www.w3schools.com/python

 

  • بازدید: 41

نوشتن دیدگاه

لطفا نظرات خود را بیان کنید. به سوالات در سریع ترین زمان پاسخ داده خواهد شد.اما به نکات زیر توجه کنید:
1. سعی کنید نظرات شما مرتبط با مقاله ی مورد نظر باشد، در غیر این صورت پاسخ داده نخواهد شد.
2. سوالات خود را به صورت کوتاه بیان کنید و از پرسیدن چند سوال به طور همزمان خودداری کنید.
3. سوال خود را به طور واضح بیان کنید و از کلمات مبهم استفاده نکنید.

ارسال