1. `@classmethod` и `@staticmethod`
Стандартные декораторы и инструменты Python: руководство с примерами
В Python стандартная библиотека предоставляет множество полезных декораторов и инструментов, упрощающих разработку. Рассмотрим ключевые из них: их назначение, синтаксис и ограничения.
1. @classmethod и @staticmethod
-
Назначение:
@classmethodпревращает метод в метод класса. Первый аргумент — сам класс (cls). Используется для создания фабричных методов или работы с классом, а не экземпляром.@staticmethodопределяет статический метод. Не получает ниself, ниcls. Это обычная функция, но внутри класса для логической группировки.
-
Синтаксис:
class MyClass: @classmethod def class_method(cls, arg1): print(f"Вызван метод класса {cls} с аргументом {arg1}") @staticmethod def static_method(arg1): print(f"Статический метод с аргументом {arg1}") -
Ограничения:
@classmethodне может быть использован для изменения состояния экземпляра (не имеет доступа кself).@staticmethodне взаимодействует ни с классом, ни с экземпляром.
2. @property, геттеры, сеттеры и делитеры
-
Назначение:
Позволяет управлять доступом к атрибутам класса, добавляя логику при чтении, записи или удалении. -
Синтаксис:
class Person: def __init__(self, name): self._name = name # Приватный атрибут @property def name(self): return self._name @name.setter def name(self, value): if not isinstance(value, str): raise ValueError("Имя должно быть строкой") self._name = value @name.deleter def name(self): print("Удаление имени") del self._name -
Ограничения:
- Геттер обязателен. Сеттер и делитер опциональны.
- Нельзя использовать для асинхронных методов.
3. @functools.wraps
-
Назначение:
Сохраняет метаданные оригинальной функции (например, имя и документацию) при использовании декораторов. -
Пример:
import functools def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print("До вызова функции") result = func(*args, **kwargs) print("После вызова") return result return wrapper @decorator def example(): """Документация функции.""" pass print(example.__name__) # "example", а не "wrapper" print(example.__doc__) # Документация сохраняется
4. Кеширование: @cached_property, @lru_cache
-
@functools.cached_property(Python 3.8+):
Кеширует результат метода класса как атрибут. Вычисляется один раз за время жизни экземпляра.from functools import cached_property class Data: def __init__(self, values): self.values = values @cached_property def stats(self): return {"sum": sum(self.values)} -
@functools.lru_cache:
Кеширует результаты функции с ограничением по размеру (Least Recently Used).from functools import lru_cache @lru_cache(maxsize=128) def factorial(n): return n * factorial(n-1) if n else 1 -
Ограничения:
- Аргументы функции должны быть хешируемыми.
cached_propertyне подходит для изменяемых данных.
5. @contextlib.contextmanager
-
Назначение:
Создает контекстный менеджер для управления ресурсами (например, файлами) с использованием генератора. -
Пример:
from contextlib import contextmanager @contextmanager def open_file(path, mode): file = open(path, mode) try: yield file finally: file.close() # Использование: with open_file("test.txt", "w") as f: f.write("Hello!")
6. @functools.total_ordering
-
Назначение:
Автоматически генерирует недостающие методы сравнения (<,>,<=,>=) на основе__eq__и одного из методов (__lt__,__le__,__gt__,__ge__). -
Пример:
from functools import total_ordering @total_ordering class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return (self.x, self.y) == (other.x, other.y) def __lt__(self, other): return (self.x + self.y) < (other.x + other.y)
7. @functools.singledispatch
-
Назначение:
Позволяет создавать перегруженные функции (разные реализации для разных типов аргументов). -
Пример:
from functools import singledispatch @singledispatch def process(arg): print("Аргумент по умолчанию:", arg) @process.register(int) def _(arg): print("Целое число:", arg) @process.register(list) def _(arg): print("Список, длина:", len(arg)) process(10) # Целое число: 10 process([1,2,3]) # Список, длина: 3
Итог
Перечисленные инструменты решают распространенные задачи: управление методами классов, безопасный доступ к атрибутам, кеширование, управление контекстом и упрощение сравнения объектов. Их правильное использование делает код чище, эффективнее и легче в поддержке. Однако важно учитывать их ограничения (например, требования к хешируемости аргументов для lru_cache или неизменяемость данных для cached_property).