Перейти к основному содержимому
Средний уровень Python2026-07-29 · 10 мин чтения

Объяснение декораторов Python: от @property до повтора логики за 15 минут (2026 г.)

Декораторы — это функция, которая отделяет «знает Python» от «свободно читает Python». Они выглядят волшебно, но они механические: @decorator для функции точно f = декоратор(f). Вот и все. Все остальное в этом уроке сводится к тому, что одна линия применяется в разных формах.

Теория одной линии

Когда вы пишете:

▶ PYTHONeditable · runs in your browser

Python преобразует его в:

▶ PYTHONeditable · runs in your browser

Вот и вся механика. @decorator_name над def запускает def_name = Decorator_name(def_name) после определения. Если вы усвоите это, декораторы навсегда перестанут быть загадочными.

Написание своего первого декоратора (60 секунд)

Декоратором является любой вызываемый объект, который принимает функцию и возвращает функцию. Типичная форма:

▶ PYTHONeditable · runs in your browser

*args, **kwargs в обертке является защитным шаблоном — он позволяет декоратору работать с любой функцией независимо от сигнатуры. Пропустите это, и вы получите TypeError: Wrapper() принимает 0 позиционных аргументов, но было дано 2 в тот момент, когда кто-то украшает функцию параметрами.

Исправление @functools.wraps

Одна тонкая ошибка: после оформления add.__name__ становится "оберткой", а не "add"`. Строки документации и подсказки типов также исчезают. Исправление - это один импорт:

▶ PYTHONeditable · runs in your browser

Правило: каждый декоратор, который вы пишете, должен использовать `@functools.wraps(fn)`. Он стоит одну строку и предотвращает целую категорию проблем отладки (самоанализ, фикстуры pytest, форматтеры loging, pickle — без него все ломается молча).

Четыре декоратора, которые вы увидите в каждой базе кода

1. @property — вычисляемые атрибуты

▶ PYTHONeditable · runs in your browser

@property делает метод вызываемым как если бы это был атрибут. Идеально подходит для производных значений, доступных только для чтения. Также существует @area.setter для пути записи, но 90% случаев использования @property доступны только для чтения.

2. @staticmethod и @classmethod

▶ PYTHONeditable · runs in your browser

@classmethod получает cls (сам класс) и используется для альтернативных конструкторов. @staticmethod не имеет ничего особенного и представляет собой простую функцию, которая просто живет внутри пространства имен класса.

3. @functools.cache — мемоизация

▶ PYTHONeditable · runs in your browser

Один из самых мощных декораторов stdlib. Автоматически запоминает функцию на основе ее аргументов. Требует, чтобы все аргументы были хешируемыми (нет списков/диктов в качестве аргументов — используйте кортежи).

4. @dataclasses.dataclass — устранение шаблона

▶ PYTHONeditable · runs in your browser

@dataclass считывает аннотации типов уровня класса и автоматически генерирует __init__, __repr__, __eq__ и (с frozen=True) __hash__. Это самое большое улучшение качества жизни в Python 3.7+.

Написание декоратора @retry (реальный пример)

Декоратор, который повторяет функцию в случае сбоя с экспоненциальной отсрочкой:

▶ PYTHONeditable · runs in your browser

Обратите внимание на три вложенные функции: retry принимает аргументы конфигурации и возвращает decorator; декоратор принимает функцию и возвращает обертку; wrapper запускает цикл повтора. Этот трехслойный шаблон выглядит так, как выглядит любой декоратор с аргументами — запоминайте форму, а не конкретный пример.

Декораторы на основе классов (редко, но полезно)

Декоратором может быть любой вызываемый объект. Классы с __call__ тоже работают:

▶ PYTHONeditable · runs in your browser

Используйте, когда декоратору необходимо удерживать состояние, которое переживет один вызов (счетчик, кеш, сегмент ограничения скорости).

Распространенные ошибки

1. Забыть `@functools.wraps` — самоанализ прерывается бесшумно.

2. Изменяемые аргументы по умолчанию в самом декораторе — здесь также встречается классическая ошибка def wrapper(x,cache=[]).

3. Украшение методов без принятия `self` — помните, что self — это всего лишь позиционный аргумент; *args, **kwargs прекрасно это воспринимает.

4. При штабелировании порядок имеет значение: @a\n@b\ndef f() равен f = a(b(f)). Читайте стопки снизу вверх.

Практика

Напишите декоратор @timing, который выводит время выполнения обернутой функции, а затем примените его к функции, которая вычисляет sum(range(10_000_000)). Весь декоратор состоит из 8 строк с functools.wraps + time.perf_counter.


Как только вы усвоите, что @x — это f = x(f), декораторы станут одной из наиболее продуктивных функций Python. Они повсюду в реальных базах кода: маршруты Flask/FastAPI (@app.route), фикстуры pytest («@pytest.fixture»), представления Django («@login_required»), валидаторы Pydantic («@field_validator»). Научившись писать их самостоятельно, вы сможете читать каждую из них.

Следующий шаг: 10 практических уроков по декоратору — создайте @retry, @memoise, @rate_limit и @requires_auth с нуля, используя настоящий Python, работающий в вашем браузере.

Готовы попробовать?

15 уроки бесплатно после бесплатной регистрации — без карты. Попробуйте платформу, а затем принимайте решение.

Начни бесплатно →

Or unlock every lesson

Pro — $12/mo, unlimited AI, cancel any time. Refund within 14 days worldwide.

See Pro plans →

Get one Python lesson + one career idea every Friday

No spam, no "buy our course now". Three bullets, every Friday. Unsubscribe with one click.