Декораторы

Обновлено: 2024-03-12
3 мин

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

@classmethod

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

Декоратор @classmethod применяется к методам класса. Он принимает первым аргументом класс (cls) вместо экземпляра класса (self).

class MyClass:
    @classmethod
    def my_class_method(cls, arg1, arg2):
        print('Class:', cls, 'arg1:', arg1, 'arg2:', arg2)

MyClass.my_class_method('a', 'b')

@staticmethod

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

Декоратор @staticmethod также применяется к методам класса. Он не принимает первый аргумент, связанный с классом.

class MyClass:
    @staticmethod
    def my_static_method(arg1, arg2):
        print('arg1:', arg1, 'arg2:', arg2)

MyClass.my_static_method('a', 'b')

@property

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

Декоратор @property используется для превращения метода в атрибут объекта. Метод, декорированный @property, может быть вызван как атрибут объекта, а не как метод.

class MyClass:
    def __init__(self, x):
        self._x = x
    
    @property
    def x(self):
        return self._x

my_obj = MyClass(10)
print(my_obj.x) # 10

@contextmanager

Декоратор @contextmanager используется для создания менеджера контекста в Python. Менеджеры контекста позволяют определять блоки кода, которые должны быть выполнены с определенными контекстными условиями, такими как открытие и закрытие файлов, установка и восстановление состояния объекта и т. д.

@contextmanager позволяет использовать функцию как менеджер контекста с использованием ключевого слова with.

from contextlib import contextmanager

@contextmanager
def my_context():
    print('entering context')
    yield
    print('exiting context')

with my_context():
    print('inside context')

@lru_cache

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

@lru_cache использует алгоритм LRU (least recently used) для автоматического удаления наиболее неиспользуемых элементов из кэша.

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(30))

Создание декоратора

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

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

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' executed in {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer
def my_func():
    time.sleep(2)

my_func()

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

Ранее Лямбда