Друкарня від WE.UA

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

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

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

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

Це, можна сказати, один з механізмів наслідування, але зі світу функціонального програмування. І так легко пишеться хороший код — жодного доступу до зміни внутрішньої поведінки, тільки розширення, а це один з принципів 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

6Довгочити
867Перегляди
18Підписники
Підтримати
На Друкарні з 4 квітня

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

Це також може зацікавити:

  • λanguage: Неформальний опис мови

    Автор пояснює, як написати парсер, інтерпретатор, компілятор, та інші складові власної мови програмування. Описується синтаксис мови, особливості реалізації функцій, умовних конструкцій та інших елементів мови.

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

    Js
  • Чому у програмістів важка робота

    Програмісти стикаються з викликами, оскільки 85% коду проекту - сторонні бібліотеки, які потребують постійного оновлення. Ринок ПЗ конкурентний, інновації часто неефективні, але необхідні для утримання позицій. Це призводить до вигорання, незважаючи на високу оплату.

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

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

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

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

Це також може зацікавити:

  • λanguage: Неформальний опис мови

    Автор пояснює, як написати парсер, інтерпретатор, компілятор, та інші складові власної мови програмування. Описується синтаксис мови, особливості реалізації функцій, умовних конструкцій та інших елементів мови.

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

    Js
  • Чому у програмістів важка робота

    Програмісти стикаються з викликами, оскільки 85% коду проекту - сторонні бібліотеки, які потребують постійного оновлення. Ринок ПЗ конкурентний, інновації часто неефективні, але необхідні для утримання позицій. Це призводить до вигорання, незважаючи на високу оплату.

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

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