برنامه نویسی

بررسی قدرت دکوراتورها در پایتون: راهنمای جامع

معرفی

اگر یک توسعه دهنده پایتون هستید که به دنبال ارتقای کد خود به سطح بعدی هستید، دکوراتورها قابلیتی هستند که قطعا باید آن را بررسی کنید. آنها ابزار قدرتمندی هستند که به شما امکان می دهند رفتار توابع یا کلاس ها را بدون تغییر کد منبع آنها تغییر دهید. اما با قدرت زیاد، مسئولیت بزرگی به همراه دارد، و دکوراتورها همچنین می توانند کد شما را در صورت استفاده بیش از حد یا نامناسب پیچیده تر و درک آن دشوارتر کنند!

بنابراین، بیایید به دنیای دکوراتورها شیرجه بزنیم و پتانسیل آنها را برای پروژه های پایتون خود باز کنیم!

دکوراتورها چیست؟

دکوراتورها توابعی هستند که تابع دیگری را به عنوان آرگومان می گیرند و یک تابع جدید را برمی گردانند. تابع جدید معمولاً یک نسخه اصلاح شده از تابع اصلی است.

برای مثال، فرض کنید تابعی داریم که دو عدد را با هم جمع می کند:

def add(x, y):
    return x + y
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

می‌توانیم دکوراتوری تعریف کنیم که پیامی را به خروجی تابع اضافه می‌کند:

def add_message(func):
    def wrapper(x, y):
        result = func(x, y)
        print("The result is:", result)
        return result
    return wrapper
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را add_message تابع یک دکوراتور است که عملکرد دیگری دارد (add) به عنوان یک آرگومان و یک تابع جدید (wrapper) که پیامی را به خروجی اضافه می کند.

می‌توانیم از دکوراتور با اعمال آن بر روی تابع اصلی استفاده کنیم:

@add_message
def add(x, y):
    return x + y

add(2, 3)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این خروجی خواهد داشت:

The result is: 5
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

دکوراتورها چگونه کار می کنند؟🤨

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

در اینجا یک مثال است:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی این کد به صورت زیر خواهد بود:

Before the function is called.
Hello!
After the function is called.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پایتون به my_decorator عملکرد با say_hello به عنوان یک استدلال را my_decorator تابع یک تابع جدید برمی گرداند (wrapper) که جایگزین می شود say_hello. وقتی زنگ میزنیم say_hello، پایتون در واقع فراخوانی می کند wrapper، که مقداری رفتار را قبل و بعد از فراخوانی تابع اصلی اضافه می کند.

انواع دکوراتور

دو نوع اصلی دکوراتور در پایتون وجود دارد: دکوراتورهای عملکرد و دکوراتورهای کلاس. همانطور که از نام آنها پیداست، دکوراتورهای تابع برای توابع اعمال می شوند، در حالی که تزئینات کلاس برای کلاس ها اعمال می شوند.

دکوراتورهای کاربردی رایج ترین نوع دکوراتور هستند. در اینجا یک مثال است:

def my_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

دکوراتورهای کلاس کمتر رایج هستند اما می توانند در شرایط خاصی مفید باشند.

در اینجا یک مثال است:

def my_decorator(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)

    return Wrapper

@my_decorator
class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def my_method(self):
        print("Hello, world!")
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایای دکوراتورها

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

  2. تفکیک نگرانی ها: آنها به تفکیک “نگرانی” کد شما کمک می کنند. به جای داشتن یک عملکرد که چندین کار را انجام می دهد، می توانید از دکوراتورها برای تقسیم عملکرد به قطعات کوچکتر و متمرکزتر استفاده کنید.

  3. افزایش خوانایی: استفاده از دکوراتورها می تواند خوانایی کد شما را بهبود بخشد. با تزئین توابع یا کلاس ها با نام های توصیفی، می توانید هدف آنها را منتقل کنید و درک کد خود را برای توسعه دهندگان دیگر آسان تر کنید.

  4. غیر تهاجمی: آنها غیر تهاجمی هستند، به این معنی که عملکرد یا کلاس اصلی را تغییر نمی دهند. در عوض، آنها یک تابع یا کلاس جدید ایجاد می‌کنند که تابع اصلی را می‌پیچد و به شما امکان می‌دهد رفتار آن را بدون تغییر کد منبع آن تغییر دهید.

خیلی مفید هستند، اینطور نیست؟

هر چیزی معایبی هم دارد، پس حالا بیایید نگاهی به معایب آنها بیندازیم

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

  1. انتزاع – مفهوم – برداشت: استفاده از دکوراتورها می تواند لایه ای از انتزاع به کد شما اضافه کند که درک آن را سخت تر می کند. این امر به ویژه در صورتی صادق است که دکوراتورهای زیادی برای کارکرد یا کلاس مشابهی داشته باشید.

  2. کارایی: استفاده از دکوراتورها می تواند بر عملکرد کد شما تأثیر بگذارد. هر دکوراتور یک لایه اضافی از فراخوانی تابع اضافه می کند که می تواند کد شما را کند کند.

  3. اشکال زدایی: اشکال زدایی کدهایی که از دکوراتورها استفاده می کند می تواند دشوارتر از اشکال زدایی کدهایی باشد که از آنها استفاده نمی کنند، به خصوص اگر با نحو دکوراتور آشنا نباشید.

ما قبلاً می دانیم که دکوراتورها چه هستند، اما اجازه دهید تا زمان استفاده از آنها را تقویت کنم!

چه زمانی از دکوراتورها استفاده کنیم؟👀

  1. افزودن قابلیت های جدید: از آنها برای افزودن عملکرد جدید به توابع یا کلاس های موجود بدون تغییر کد منبع آنها استفاده کنید. این می تواند گسترش و سفارشی کردن کد خود را در طول زمان آسان تر کند.

  2. اصلاح رفتار: از آنها برای تغییر رفتار توابع یا کلاس ها برای یک مورد خاص استفاده کنید، مانند اضافه کردن گزارش یا رسیدگی به خطا.

  3. تفکیک نگرانی ها: از آنها برای کپسوله کردن رفتار خاص در توابع جداگانه استفاده کنید. این می تواند کد شما را ماژولارتر کرده و نگهداری آن را آسان تر کند.

نمونه هایی از استفاده از دکوراتورها

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

1. اضافه کردن ورود به سیستم:

می‌توانید از دکوراتور برای افزودن «logging» به یک تابع استفاده کنید.

در اینجا یک مثال است:

def log(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args {args} and kwargs {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@log
def add(x, y):
    return x + y

add(2, 3)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این خروجی خواهد داشت:

Calling add with args (2, 3) and kwargs {}
5
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

2. زمان بندی اجرا:

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

در اینجا یک مثال است:

import time

def timeit(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start} seconds")
        return result
    return wrapper

@timeit
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n-1) + fib(n-2)

print(fib(30))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی خواهد بود:

fib took 0.41451382637023926 seconds
832040
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

3. نتایج ذخیره سازی:

می‌توانید از دکوراتور برای ذخیره کردن نتایج یک تابع استفاده کنید.

در اینجا یک مثال است:

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args in cache:
            return cache[args]
        else:
            result = func(*args)
            cache[args] = result
            return result
    return wrapper

@memoize
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n-1) + fib(n-2)

print(fib(30))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی خواهد بود:

832040
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه

برای استفاده مؤثر از دکوراتورها، درک هدف، موارد استفاده و محدودیت‌های آن‌ها مهم است. با استفاده از دکوراتورها در صورت نیاز، می توانید از قدرت آنها استفاده کنید و قابلیت های جدیدی را به کد پایتون خود اضافه کنید. من فکر می‌کنم که تا به حال، شما بچه‌ها آماده هستید تا با دکوراتورها آزمایش کنید و پتانسیل آن‌ها را باز کنید تا پروژه‌های پایتون خود را به سطح بعدی برسانید؛)


بیایید وصل شویم!

توییتر

✨ Github

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا