Ответ
В Python декораторы — это функции, которые изменяют или расширяют поведение других функций или методов без изменения их исходного кода. Вот основные встроенные декораторы и те, что часто используются из стандартной библиотеки functools
:
-
@property
- Назначение: Позволяет превратить метод класса в атрибут, обеспечивая контролируемый доступ к данным (геттер).
- Почему: Используется для инкапсуляции, создания "вычисляемых" атрибутов и обеспечения валидации при установке значений (через
@<attr>.setter
). Улучшает читаемость кода, позволяя обращаться к методам как к атрибутам. -
Пример:
class Circle: def __init__(self, radius): self._radius = radius # Приватный атрибут @property def radius(self): """Геттер для радиуса.""" return self._radius @radius.setter def radius(self, value): """Сеттер для радиуса с валидацией.""" if value < 0: raise ValueError("Радиус не может быть отрицательным") self._radius = value c = Circle(10) print(c.radius) # Вызывает геттер: 10 c.radius = 15 # Вызывает сеттер print(c.radius) # 15 # c.radius = -5 # Вызовет ValueError
-
@classmethod
- Назначение: Объявляет метод как метод класса. Первый аргумент такого метода — сам класс (
cls
), а не экземпляр (self
). - Почему: Полезен для создания альтернативных конструкторов (фабричных методов), которые могут создавать экземпляры класса различными способами, или для операций, которые относятся ко всему классу, а не к конкретному экземпляру.
-
Пример:
class MyClass: def __init__(self, data): self.data = data @classmethod def from_string(cls, string_data): """Фабричный метод для создания экземпляра из строки.""" return cls(int(string_data)) @classmethod def default_instance(cls): """Создает экземпляр с данными по умолчанию.""" return cls(0) obj1 = MyClass(10) obj2 = MyClass.from_string("20") obj3 = MyClass.default_instance() print(obj1.data, obj2.data, obj3.data) # Вывод: 10 20 0
- Назначение: Объявляет метод как метод класса. Первый аргумент такого метода — сам класс (
-
@staticmethod
- Назначение: Объявляет метод как статический. Он не принимает ни
self
, ниcls
в качестве первого аргумента и ведет себя как обычная функция, логически связанная с классом. - Почему: Используется для утилитарных функций, которые не зависят от состояния экземпляра или класса, но логически принадлежат классу. Помогает организовать код.
-
Пример:
class MathUtils: @staticmethod def add(a, b): """Статический метод для сложения двух чисел.""" return a + b @staticmethod def multiply(a, b): """Статический метод для умножения двух чисел.""" return a * b print(MathUtils.add(5, 3)) # Вывод: 8 print(MathUtils.multiply(5, 3)) # Вывод: 15
- Назначение: Объявляет метод как статический. Он не принимает ни
-
@functools.cache
(Python 3.9+)- Назначение: Декоратор для мемоизации (кеширования) результатов функции. Сохраняет результаты вызовов функции с одними и теми же аргументами.
- Почему: Значительно повышает производительность для чистых функций (без побочных эффектов), которые часто вызываются с одними и теми же аргументами и выполняют дорогостоящие вычисления.
-
Пример:
import functools import time @functools.cache def fibonacci(n): if n <= 1: return n return fibonacci(n - 1) + fibonacci(n - 2) start_time = time.time() fibonacci(30) # Вычисляется один раз print(f"Time for first call: {time.time() - start_time:.4f}s") start_time = time.time() fibonacci(30) # Результат берется из кеша print(f"Time for second call: {time.time() - start_time:.4f}s")
-
@functools.lru_cache
- Назначение: Декоратор для кеширования результатов функции с ограничением по размеру (Least Recently Used - наименее недавно использованные).
- Почему: Позволяет управлять потреблением памяти кешем, автоматически удаляя наименее недавно использованные элементы, когда кеш достигает максимального размера. Идеален для функций, работающих с ограниченным набором часто используемых входных данных.
-
Пример:
import functools @functools.lru_cache(maxsize=128) # Кеш на 128 последних результатов def get_web_page(url): """Имитация дорогостоящего запроса к веб-странице.""" print(f"Fetching {url}...") # time.sleep(1) # Имитация задержки return f"Content of {url}" print(get_web_page("http://example.com/page1")) # Вывод: Fetching http://example.com/page1... print(get_web_page("http://example.com/page2")) # Вывод: Fetching http://example.com/page2... print(get_web_page("http://example.com/page1")) # Результат берется из кеша, без 'Fetching...'