Python: Функции
2026-02-26 20:31 Diff

В программировании часто возникают задачи, когда нужно добавить поведение к уже существующим функциям или классам. Например, логирование, проверку входных данных или замер времени выполнения функции. В таких случаях использование декораторов может значительно упростить решение задачи.

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

Что такое декораторы

Ранее мы рассматривали как можно "запомнить" передаваемые в функцию значения с помощью замыканий. Напомним как выглядит синтаксис:

В этом примере мы создаем функцию outer(), которая принимает аргумент arg1 и возвращает внутреннюю функцию inner(). Внутренняя функция принимает аргумент arg2 и возвращает сумму arg1 и agr2.

Может запутать одновременное определение функции и возврат ее же. Но если мы вспомним, что определение функции это присваивание функции имени переменной, а также, что функции это данные, то пример можно представить как:

Мы заменили именованную функцию лямбдой, и теперь присваивание ничем не отличается, как если бы мы присвоили переменной inner число или строку.

Но если функции всего лишь данные, то можно ли их также "запоминать" в замыканиях?

Остановимся и разберем пример выше. В нем мы создаем замыкание, но теперь, вместо числа в замыкание передается функция. Внешняя функция запомнила переданную в нее функцию. Осталось лишь передать аргументы и вызвать замкнутую функцию с ними. В дополнение, мы смогли распечатать переданную функцию и ее аргументы, при этом код самой функции square() мы не меняли.

Функции выше называются декораторами. Декораторы в Python — это функции, которые принимают другую функцию в качестве аргумента, добавляют к ней дополнительную функциональность и возвращают функцию с измененным поведением. Декораторы позволяют изменять поведение функций и классов с помощью добавления или изменения их функциональности без изменения самого кода.

Также, как вы могли заметить, декораторы это частный случай функции высшего порядка (принимаем функцию) и использования замыкания вместе.

Использование декораторов

Декораторы используются в Python повсеместно: для логирования, кеширования, добавления нового функционала, используются в тестовых и веб-фреймворках.

Предположим, что у нас есть функция, которая суммирует числа:

Создадим декоратор, который добавит к этой функции функциональность для отладки:

Этот декоратор принимает функцию в качестве аргумента и возвращает новую функцию-обертку, которая добавляет отладочные сообщения в процесс выполнения исходной функции. Заметьте, что внутренняя функция принимает сразу все аргументы с помощью *args и **kwargs. Так мы можем создавать "всеядные" обертки.

Применим этот декоратор к функции sum():

Проблема в коде выше, что теперь функция называется debugged_sum(), и нужно будет изменить весь код, что использовал sum(). Но ведь имя функции это всего лишь имя переменной, и мы можем перезаписать новую, декорированную функцию в ту же переменную.

Теперь функция sum() будет выполняться с дополнительными отладочными сообщениями. А также весь код, использующий функцию sum() будет использовать новую функцию.

Чтобы не добавлять запись вида func = decorator(func) каждый раз, в Python добавили синтаксический сахар - @decorator

Также мы можем создавать несколько декораторов для одной функции, которые будут применяться последовательно:

В этом примере сначала применится декоратор времени выполнения, а затем отладочный декоратор.

Состояние

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

Но замыкания позволяют запоминать значения и использовать их в последующих вычислениях.

Замыкания, как и декораторы, позволяют нам создавать на базе функций собственные объекты и систему управления ими.

Декораторы с параметрами

Что если мы хотели бы вызывать обернутую функцию с разными настройками? Для этого нам понадобятся декораторы с параметрами.

Общий синтаксис декоратора с параметрами выглядит так:

К обычному декоратору мы добавляем еще один слой с параметрами. И, конечно, в качестве параметров мы можем передавать другие функции:

И даже функции с собственными параметрами, используя замыкания:

Декоратор filter_by() принимает функцию фильтрации less_than(), затем применяет ее к аргументам обернутой функции, и вызывает обернутую функцию с новыми аргументами.

Выводы

Мы изучили декораторы, мощный механизм для расширения функций. Существует большое количество готовых декораторов, доступных в стандартной библиотеке Python и других библиотеках. Некоторые из них позволяют кэшировать результаты функций, обеспечивать авторизацию и безопасность, профилировать код, проверять типы данных и многое другое.

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

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