Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Декораторы Python: Функции

Представьте, что вам захотелось иметь возможность выводить на печать все результаты вызова некой функции. Однако саму функцию модифицировать не хочется, а вместо этого вы желаете получить универсальный инструмент, пригодный для использования с любыми функциями.

Давайте реализуем такую функцию, для чего воспользуемся ФВП (функцией высшего порядка):

def printing(function):
    def inner(*args, **kwargs):
        result = function(*args, **kwargs)
        print('result =', result)
        return result
    return inner

def add_one(x):
    return x + 1

add_one = printing(add_one)
y = add_one(10)
# => result = 11
y
# 11

Сначала разберёмся с функцией printing. Эта функция создаёт замыкание inner, которое принимает любые аргументы, применяет к ним функцию, печатает результат и тут же возвращает его. Заметьте, в определении inner я использовал аргументы *args, **kwargs, которые функция без изменения передаёт замкнутой функции function — именно так в Python объявляют "всеядные" функции, которые "пробрасывают" любые комбинации аргументов.

Теперь посмотрим на пример применения printing. В примере я заменил функцию обёрнутым (wrapped) вариантом через присваивание старому имени функции нового значения. Да, функции в Python — обычные переменные в той области видимости, где были объявлены!

Имя "printing" ("печатающий") я выбрал неспроста — подобные обёртки над функциями часто называют в похожей манере. Ведь и по смыслу поведение, которое добавляет обёртка к исходной функции, служит дополнением для этой функции. И читается printing(add_one) практически по-человечески: "добавить единицу, печатая на экран (результат)".

Подобное оборачивание — довольно частая операция в коде, широко использующем функции высшего порядка. Авторы языка Python даже завели для удобного использования функций-обёрток специальный синтаксис! Вот эти самые функции-обёртки вместе с синтаксисом оборачивания называются декораторами.

Тут я вынужден предупредить, что те из вас, кто знаком с паттерном проектирования "Декоратор", могут смело забыть всё, что они знали о нём! Дело в том, что декораторы в Python — сугубо самостоятельная вещь, а не реализации упомянутого паттерна. Те, кому словосочетание "паттерн Декоратор" ничего не говорит, могут не обращать на это замечание внимания :)

Синтаксис применения декоратора

Применения декоратора printing к функции add_one с использованием специального синтаксиса можно записать так:

@printing
def add_one(x):
    return x + 1

Имя декоратора пишется на строчке, предшествующей заголовку функции, а перед именем пишется символ @. После такого применения декоратора нам уже не нужно "переприсваивать" функцию (add_one = printing(add_one))!

Применение даже одного декоратора становится удобнее с таким синтаксисом, но применять подобным образом можно сколько угодно декораторов! Выглядеть это будет так:

@logging
@printing
@cached
def foo():
    # …

Что будет равнозначно коду

foo = cached(foo)
foo = printing(foo)
foo = logging(foo)
# или в одну строку
foo = logging(printing(cached(foo)))

Обратите внимание и запомните: оборачивание происходит сначала в ближайшие к имени функции обёртки, как бы "изнутри наружу" — cached, затем printing и в конце logging.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
1 июня 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»