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

4 سال پیش

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

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

پیشنهاد ویژه : پکیج آموزش صفر تا صد پایتون

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

پایتون ویژگی جالبی به نام دکوراتورها برای افزودن قابلیت به کد موجود دارد.

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

پیش نیازهای یادگیری دکوراتورها در پایتون

به منظور درک در مورد دکوراتور، ابتدا باید چند نکته اساسی را در پایتون بدانیم.

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

به عنوان مثال.

def first(msg):
    print(msg)


first("Hello")

second = first
second("Hello")

 

خروجی

Hello
Hello

 

هنگامی که کد را اجرا می کنید ، هر دو تابع اول و دوم خروجی یکسانی دارند. در اینجا، نام های اول و دوم به همان شی تابع اشاره دارند.

حالا همه چیز عجیب و غریب می شود.

توابع را می توان به عنوان آرگومان یک تابع دیگر منتقل کرد.

اگر از توابعی مانند filter ،map و reduce در پایتون استفاده کرده باشید، با این موضوع آشنایی دارید.

چنین توابعی را که توابع دیگر را به عنوان آرگومان می گیرند، توابع مرتبه بالاتر نیز می نامند. در اینجا مثالی از چنین توابعی آورده شده است.

def inc(x):
    return x + 1


def dec(x):
    return x - 1


def operate(func, x):
    result = func(x)
    return result

 

ما تابع را به شرح زیر فراخوانی می کنیم.

>>> operate(inc,3)
۴
>>> operate(dec,3)
۲

 

به علاوه، یک تابع می تواند تابع دیگری را برگرداند.

def is_called():
    def is_returned():
        print("Hello")
    return is_returned


new = is_called()

# Outputs "Hello"
new()

 

خروجی

Hello

 

در اینجا، ()iis_returned یک تابع تو در تو است که هر بار ()is_called فراخوانی شود تعریف شده و برمی گردد.

دکوراتورها در پایتون

در واقع ، هر شیئی که متد ویژه ()__call __  را اجرا کند ، قابل فراخوانی است. بنابراین ، در اساسی ترین مفهوم  دکوراتور یک قابل فراخوانی است که قابل فراخوانی قابل را برمی گرداند.

در واقع ، یک دکوراتور  یک تابع را می گیرد، برخی از قابلیت ها را به آن اضافه می کند و آن را برمی گرداند.

def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner


def ordinary():
    print("I am ordinary")

 

وقتی کدهای زیر را بصورت پوسته اجرا می کنید،

>>> ordinary()
I am ordinary

>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary

 

در مثالی که در بالا نشان داده شده، ()make_pretty یک دکوراتور است. در مرحله تخصیص، داریم که:

pretty = make_pretty(ordinary)

 

تابع ()ordinary دکوریت می‌شود و به تابع برگشت داده شده pretty گفته می شود.

می توانیم ببینیم که تابع دکوراتور برخی از قابلیت های جدید را به تابع اصلی اضافه کرده است. این شبیه بسته بندی هدیه است. دکوراتور به عنوان یک بسته بندی عمل می کند. ماهیت شیئی که تزئین شده است (هدیه واقعی داخل) تغییری نمی کند. اما اکنون، بسیار زیبا به نظر می رسد (از زمانی که تزئین شده است).

به طور کلی، ما یک تابع را دکوریت می کنیم و دوباره آن را استفاده می کنیم.

ordinary = make_pretty(ordinary).

 

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

ما می توانیم از نماد @ به همراه نام تابع دکوراتور استفاده کنیم و آن را  بالای تعریف تابع برای دکوریت شدن قرار داد. مثلا،

@make_pretty
def ordinary():
    print("I am ordinary")

 

برابر است با

def ordinary():
    print("I am ordinary")
ordinary = make_pretty(ordinary)

 

 

تابع های دکوراتور با پارامترها در پایتون

دکوراتور فوق ساده بود و فقط با توابعی کار می کرد که هیچ پارامتری نداشتند. اگر توابعی داشته باشیم که پارامترهایی مانند موارد زیر داشته باشند

def divide(a, b):
    return a/b

 

این تابع دارای دو پارامتر a و b است. ما می دانیم که اگر در b به صورت مقدار ۰ پاس داده شود، خطایی ایجاد می کند.

>>> divide(2,5)
۰٫۴
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero

 

حالا بیایید یک دکوراتور بسازیم تا این مورد را که باعث خطا می شود بررسی کند.

def smart_divide(func):
def smart_divide(func):
    def inner(a, b):
        print("I am going to divide", a, "and", b)
        if b == 0:
            print("Whoops! cannot divide")
            return

        return func(a, b)
    return inner


@smart_divide
def divide(a, b):
    print(a/b)

 

در صورت بروز خطا، این پیاده سازی جدید None را برمی گرداند.

>>> divide(2,5)
I am going to divide 2 and 5
۰٫۴

>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide

 

به این ترتیب ، ما می توانیم توابعی را که پارامتر می گیرند، دکوریت کنیم.

یک ناظر دقیق متوجه می شود که پارامترهای تابع  تو در تو ()inner در داخل دکوراتور همان پارامترهای تابعی است که دکوریت می کند. با در نظر گرفتن این نکته، اکنون می توانیم دکوراتور کلی ایجاد کنیم که با هر تعداد پارامتر کار می کنند.

در پایتون، این کار به صورت تابع (function(*args, **kwargs) انجام می شود. به این ترتیب، args انبوهی از استدلالهای موقعیتی و kwargs دیکشنری آرگومان های کلمه کلیدی خواهند بود. نمونه ای از چنین دکوراتورها:

def works_for_all(func):
    def inner(*args, **kwargs):
        print("I can decorate any function")
        return func(*args, **kwargs)
    return inner

 

زنجیر کردن دکوراتورها در پایتون

چندین دکوراتور را می توان در پایتون زنجیر زد.

این بدان معناست که یک تابع را می توان چندین بار با دکوراتورهای مختلف (یا همان) دکوریت کرد. ما به سادگی دکوراتورها را بالاتر از تابع مورد نظر قرار می دهیم.

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner


def percent(func):
    def inner(*args, **kwargs):
        print("%" * 30)
        func(*args, **kwargs)
        print("%" * 30)
    return inner


@star
@percent
def printer(msg):
    print(msg)


printer("Hello")

 

خروجی

******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************

 

نحو بالا برای:

@star
@percent
def printer(msg):
    print(msg)

 

برابر است با:

def printer(msg):
    print(msg)
printer = star(percent(printer))

 

نظم و ترتیب ما در  زنجیر کزددن دکوراتوز مهم است. اگر ما دستور را معکوس کرده بودیم ،

@percent
@star
def printer(msg):
    print(msg)

 

خروجی

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
Hello
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

منبع.

لیست جلسات قبل آموزش برنامه نویسی پایتون

  1. آموزش نصب و اجرای برنامه نویسی پایتون
  2. کلیدواژه ها و شناسه های برنامه نویسی پایتون
  3. دستورات، تورفتگی ها و کامنت ها در برنامه نویسی پایتون
  4. متغیرها، ثابت ها و لیترال ها در برنامه نویسی پایتون 
  5. انواع داده ها در برنامه نویسی پایتون
  6. تبدیل نوع در برنامه نویسی پایتون
  7. ورودی، خروجی و وارد کردن در برنامه نویسی پایتون
  8. عملگرها در برنامه نویسی پایتون
  9. نام و دامنه در برنامه نویسی پایتون
  10. دستور شرطی if…else در برنامه نویسی پایتون
  11. حلقه for در برنامه نویسی پایتون
  12. حلقه while در برنامه نویسی پایتون
  13. دستورات break و continue در برنامه نویسی پایتون
  14. دستور pass در برنامه نویسی پایتون
  15. توابع در برنامه نویسی پایتون
  16. آرگومان تابع در برنامه نویسی پایتون
  17. تابع بازگشتی در برنامه نویسی پایتون
  18. تابع بی نام/ تابع لامبدا در برنامه نویسی پایتون
  19. متغیرهای سراسری، محلی و غیر محلی در برنامه نویسی پایتون
  20. کلیدواژه global در برنامه نویسی پایتون
  21. ماژول های برنامه نویسی پایتون
  22. پکیج ها در برنامه نویسی پایتون
  23. اعداد و تبدیل نوع داده در برنامه نویسی پایتون 
  24. لیست در برنامه نویسی پایتون
  25. تاپل در برنامه نویسی پایتون 
  26. رشته ها در برنامه نویسی پایتون
  27. مجموعه ها در برنامه نویسی پایتون
  28. دیکشنری در برنامه نویسی پایتون
  29. عملیات ورودی/خروجی در برنامه نویسی پایتون 
  30. دایرکتوری و مدیریت فایل ها در برنامه نویسی پایتون
  31. خطاها و استثناهای توکار در برنامه نویسی پایتون
  32. مدیریت استثناها در برنامه نویسی پایتون
  33. استثناهای تعریف شده توسط کاربر در برنامه نویسی پایتون
  34. برنامه ‌نویسی شی گرا در پایتون
  35. اشیا و کلاس ها در برنامه نویسی پایتون
  36. وراثت در برنامه نویسی پایتون
  37. وراثت چندگانه در برنامه نویسی پایتون
  38. سربارگذاری عملگرها در برنامه نویسی پایتون
  39. تکرار کننده ها در برنامه نویسی پایتون
  40. Generator در برنامه نویسی پایتون
  41. بستار در برنامه نویسی پایتون
0
برچسب ها :
نویسنده مطلب erfan molaei

دیدگاه شما

بدون دیدگاه