что делает декоратор в python

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

1. Основное представление о декораторах

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

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

Пример простого декоратора:

python
def my_decorator(func): def wrapper(): print("До вызова функции") func() print("После вызова функции") return wrapper def say_hello(): print("Привет!") # Применяем декоратор decorated_function = my_decorator(say_hello) decorated_function() # Вывод: # До вызова функции # Привет! # После вызова функции

В этом примере:

  • my_decorator — это декоратор.

  • Он принимает функцию say_hello в качестве аргумента и возвращает новую функцию wrapper, которая вызывает say_hello и добавляет дополнительный функционал (печатает строки до и после вызова).

2. Использование синтаксиса @

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

python
@my_decorator def say_hello(): print("Привет!") say_hello() # Вывод: # До вызова функции # Привет! # После вызова функции

В этом примере @my_decorator эквивалентно записи say_hello = my_decorator(say_hello).

3. Декораторы с аргументами

Если ваша функция принимает параметры, декоратор также должен учитывать это и правильно передавать аргументы. Для этого можно использовать *args и **kwargs, чтобы передать аргументы от исходной функции в обёрнутую.

Пример:

python
def my_decorator(func): def wrapper(*args, **kwargs): print("До вызова функции") result = func(*args, **kwargs) print("После вызова функции") return result return wrapper @my_decorator def say_hello(name): print(f"Привет, {name}!") say_hello("Иван") # Вывод: # До вызова функции # Привет, Иван! # После вызова функции

Здесь:

  • Мы используем *args и **kwargs, чтобы декоратор мог работать с любыми аргументами, которые передаются функции say_hello.

4. Декораторы с возвращаемыми значениями

Декоратор может также изменять возвращаемое значение функции, возвращая результат по-своему. Это может быть полезно, например, для кэширования результатов.

Пример декоратора, который возвращает результат из кэша, если такой результат уже был вычислен:

python
def cache_result(func): cache = {} def wrapper(*args): if args in cache: print("Возвращаем результат из кэша") return cache[args] else: print("Вычисляем результат") result = func(*args) cache[args] = result return result return wrapper @cache_result def slow_add(x, y): return x + y print(slow_add(2, 3)) # Вывод: Вычисляем результат, 5 print(slow_add(2, 3)) # Вывод: Возвращаем результат из кэша, 5

Здесь декоратор cache_result кэширует результаты функции slow_add на основе переданных аргументов.

5. Декораторы с аргументами

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

Пример:

python
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): func(*args, **kwargs) return wrapper return decorator @repeat(3) def say_hello(): print("Привет!") say_hello() # Вывод: # Привет! # Привет! # Привет!

Здесь декоратор repeat принимает параметр n, который указывает, сколько раз нужно вызвать функцию say_hello.

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

Python предоставляет несколько встроенных декораторов, таких как @staticmethod, @classmethod, и @property, которые изменяют поведение методов в классах.

  • @staticmethod: делает метод статическим, то есть метод, который не зависит от экземпляра класса.

  • @classmethod: делает метод методом класса, то есть он работает с самим классом, а не с экземпляром.

  • @property: позволяет определить метод как свойство, то есть доступ к нему будет осуществляться как к атрибуту.

Пример с использованием @staticmethod и @classmethod:

python
class MyClass: @staticmethod def static_method(): print("Это статический метод") @classmethod def class_method(cls): print(f"Это метод класса {cls.__name__}") MyClass.static_method() # Вывод: Это статический метод MyClass.class_method() # Вывод: Это метод класса MyClass

7. Декораторы для методов

При использовании декораторов для методов важно помнить, что методы, как правило, имеют доступ к объекту (через self) или классу (через cls). Если вы применяете декоратор к методу, нужно учесть, что первый аргумент — это либо self (для обычных методов), либо cls (для методов класса).

Пример:

python
def method_decorator(func): def wrapper(self, *args, **kwargs): print(f"Вызов метода {func.__name__} с аргументами {args}") return func(self, *args, **kwargs) return wrapper class MyClass: @method_decorator def some_method(self, a, b): return a + b obj = MyClass() print(obj.some_method(2, 3)) # Вывод: # Вызов метода some_method с аргументами (2, 3) # 5

8. Заключение

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

  • Логирование

  • Кэширование

  • Проверка прав доступа

  • Изменение аргументов или результатов

  • Добавление функциональности без изменения исходного кода функции

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

Scroll to Top

Карта сайта