Декораторы и модификация поведения функций
Декораторы в Python — это мощный инструмент для модификации поведения функций или методов без изменения их кода. Они позволяют добавлять функциональность к существующим функциям или методам, оборачивая их в другие функции. Декораторы особенно полезны для выполнения задач, таких как логирование, проверка прав доступа, кэширование результатов и другие задачи.
Основы декораторов
Простейший декоратор
Декоратор — это функция, которая принимает другую функцию в качестве аргумента и возвращает новую функцию, которая расширяет или изменяет поведение оригинальной функции.
Вывод:
В этом примере декоратор my_decorator
оборачивает функцию say_hello
, добавляя дополнительный функционал до и после ее вызова.
Декораторы с аргументами
Если функция, которую вы декорируете, принимает аргументы, декоратор также должен их обрабатывать. Можно использовать *args
и **kwargs
, чтобы передать произвольное количество аргументов и ключевых слов.
Вывод:
Декораторы с возвращаемыми значениями
Декораторы могут возвращать значения, которые вычисляются внутри wrapper
функции.
Вывод:
В этом примере декоратор double_return
удваивает результат функции get_number
.
Примеры использования декораторов
Логирование
Декораторы могут использоваться для добавления логирования к функциям.
Вывод:
Проверка прав доступа
Декораторы могут проверять права доступа перед выполнением функции.
Вывод:
Если user
не является администратором, будет вызвано исключение PermissionError
.
Кэширование результатов
Декораторы могут использоваться для кэширования результатов функций.
Вывод:
Во втором вызове compute_expensive_operation
результат берется из кэша, что ускоряет выполнение.
Вложенные декораторы
Декораторы могут быть вложенными. В этом случае они применяются последовательно, начиная с самой внутренней функции.
Вывод:
В этом примере decorator2
применяется к функции greet
первой, затем decorator1
применяется к результату.
Декораторы с аргументами
Декораторы с аргументами позволяют создавать более гибкие и настраиваемые декораторы, которые могут изменять своё поведение в зависимости от переданных аргументов. Основная идея заключается в создании декоратора, который сам является функцией, принимающей аргументы, и возвращает другой декоратор.
Вот как можно создать и использовать декораторы с аргументами:
Пример 1: Простейший декоратор с аргументами
Создадим декоратор, который принимает параметр и использует его для модификации поведения функции.
Вывод:
В этом примере декоратор repeat
принимает аргумент n
, который указывает, сколько раз нужно выполнить функцию greet
.
Пример 2: Логирование с аргументами
Создадим декоратор, который логирует сообщения с разным уровнем важности, передавая уровень как аргумент.
Вывод:
Декоратор log
использует параметр level
, чтобы указать уровень важности сообщения.
Создадим декоратор, который проверяет права доступа на основе переданных ролей.
Вывод:
Если user
не имеет роли 'admin'
, будет вызвано исключение PermissionError
.
Пример 4: Декоратор для кэширования с аргументами
Создадим декоратор для кэширования результатов функции с использованием заданного размера кэша.
Вывод:
В этом примере декоратор cache_with_size
создает кэш с ограниченным размером для функции compute_expensive_operation
.
@wraps
wraps
— это декоратор из модуля functools
в Python, который используется для правильного оформления декорированных функций. При создании собственных декораторов, когда вы декорируете одну функцию другой, важные метаданные исходной функции, такие как её имя, строка документации (docstring) и аннотации, могут быть потеряны. Декоратор @functools.wraps
помогает сохранить эти атрибуты.
Как работает wraps
wraps
Когда вы создаёте свой декоратор, вы, вероятно, пишете что-то вроде:
Если вы используете этот декоратор, декорированная функция теряет своё имя и строку документации:
Чтобы избежать этой проблемы, можно использовать @functools.wraps
:
Преимущества использования wraps
wraps
Сохранение метаданных: имя функции, строка документации и другие атрибуты сохраняются у декорированной функции.
Улучшение отладки: при отладке или логировании имя функции и строка документации остаются корректными.
Работа с инструментами и библиотеками: многие библиотеки и инструменты (например, тестовые фреймворки) полагаются на атрибуты функций, такие как имя и строка документации.
Использование @functools.wraps
— это лучшая практика при создании собственных декораторов в Python. Он гарантирует, что декорированные функции сохраняют свои метаданные, что делает ваш код более читаемым, поддерживаемым и удобным для отладки.
Заключение
Декораторы в Python — это мощный и гибкий инструмент для модификации поведения функций и методов. Они позволяют добавлять функциональность, не изменяя код исходных функций, что делает код более модульным и легко расширяемым. Декораторы могут использоваться для выполнения различных задач, таких как логирование, проверка прав доступа, кэширование и другие.
Декораторы с аргументами предоставляют гибкий способ модификации поведения функций и методов, позволяя настраивать их поведение в зависимости от переданных параметров. Это делает их очень полезными для создания настраиваемых решений, таких как логирование, кэширование и проверка прав доступа.
Last updated