Пайтон: декоратори - як і навіщо?

Входячи в пайтон-розробку, кожен дев точно стикався з цим явищем, бо декоратори присутні у каждому, просто у каждому сучасному фреймворці Пайтона

То, що ж це таке?

Декоратори — функції, що обгортують іншу функцію, надаючи додаткову логіку або взагалі замінюючи її. Замість функцій можуть бути використані класи, але це вже зовсім інша історія 😅

Це, можна сказати, один з механізмів наслідування, але зі світу функціонального програмування. І так легко пишеться хороший код — жодного доступу до зміни внутрішньої поведінки, тільки розширення, а це один з принципів SOLID 🤓
Думаю саме тому декоратори стали такими популярними 😍

Приклади використання

Реєстрація функції як callback, для серверу чи бота

# https://fastapi.tiangolo.com/#example
@app.get('/items/{item_id}')
def read_item(item_id: int, q: Union[str, None] = None):
    return {'item_id': item_id, 'q': q}

Просте кешування

# https://docs.python.org/3/library/functools.html#functools.lru_cache
@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

Промаркувати функцію для подальшого використання, не змінюючи її
(в цьому випадку у функції додається атрибут pytestmark)

# https://docs.pytest.org/en/7.1.x/how-to/skipping.html#skipping-test-functions
import sys


@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
def test_function():
    ...

Заміна метода дескриптором

# https://docs.python.org/3/library/functions.html#property
class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage

Що ж, пора й самому щось написати ? 😁

Приклад написання

def timeit(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = f(*args, **kwargs)
        total_time = time.perf_counter() - start_time
        print(
            f'Function {f.__name__}, args: {args}, kwargs: {kwargs} '
            f'took {total_time:.2f} seconds'
        )
        return result
    return wrapper

Тут, ми водночас, використовуємо інший декоратор — @functools.wraps, який є каноном для функцій-обгорток, і дозволяє нам не змінювати назву оригінальної функції. Без нього, після створення функції з використанням декоратора, кінцевий користувач буде бачити в логах незрозумілу для нього функцію wrapper

Насправді, в декораторах немає нічого складного, якщо розуміти, що нижні два приклади є цілком ідентичними для Пайтону:

@timeit
def add(a, b):
    return a + b
def add(a, b):
    return a + b
add = timeit(add)

І тут єдине, що робить Пайтон — дає дуже зручний спосіб використання

У прикладі з timeit та lru_cache, додаткова логіка застосовується при виклику функції, і викликається оригінальна функція, без зміни аргументів. Не бачу особливого сенсу розбирати деталі, але якщо є такий запит, пишіть у коментарях 💬

Q&A

Якщо у вас все ще залишились запитання про декоратори у пайтоні, як чи навіщо їх писати — завжди готовий відповісти у коментарях

Усім добра та мирного неба над головою ❤️

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Вітя
Вітя@kor0p

Python SDET @ ajax.systems

843Прочитань
10Автори
18Читачі
Підтримати
На Друкарні з 14 квітня

Більше від автора

  • Пайтон: дескриптори - що це???

    Можливо, навіть далеко не всі чули, що таке дескриптори, але точно всі використовували їхЯ кажу це так впевнено, оскільки @property є дескриптором

    Теми цього довгочиту:

    Програмування
  • Майбутнє фронтенду — Пайтон?🤔

    PyWeb - фронтенд фреймворк, написаний на Пайтоні, мого авторства 🤓 Щоб запускати Пайтон в браузері використовується Pyodide та WebAssembly

    Теми цього довгочиту:

    Python

Вам також сподобається

  • Кібервійна в Україні так само важлива, як і битва в окопах

    Українська та російська сторони ведуть кібервійну, спрямовану на викрадення даних та сіяння паніки. Російські атаки вже давали тривожний дзвінок, вимикаючи електрику та зламуючи банки та енергетичні компанії. Україна змогла підвищити свою ефективність, але загроза залишається.

    Теми цього довгочиту:

    Війна
  • Що таке патерни проєктування?

    Патерни проєктування подібні до стандартних конструкцій у будівництві. Наприклад, "патерн Фасад" відповідає фасаду будинку, який приховує деталі і надає простий інтерфейс. "Патерн Одинак" подібний до створення лише одного ключа для доступу до чогось цінного.

    Теми цього довгочиту:

    Програмування

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Вам також сподобається

  • Кібервійна в Україні так само важлива, як і битва в окопах

    Українська та російська сторони ведуть кібервійну, спрямовану на викрадення даних та сіяння паніки. Російські атаки вже давали тривожний дзвінок, вимикаючи електрику та зламуючи банки та енергетичні компанії. Україна змогла підвищити свою ефективність, але загроза залишається.

    Теми цього довгочиту:

    Війна
  • Що таке патерни проєктування?

    Патерни проєктування подібні до стандартних конструкцій у будівництві. Наприклад, "патерн Фасад" відповідає фасаду будинку, який приховує деталі і надає простий інтерфейс. "Патерн Одинак" подібний до створення лише одного ключа для доступу до чогось цінного.

    Теми цього довгочиту:

    Програмування