Найти в Дзене

Стандартные декораторы и инструменты Python: руководство с примерами

В Python стандартная библиотека предоставляет множество полезных декораторов и инструментов, упрощающих разработку. Рассмотрим ключевые из них: их назначение, синтаксис и ограничения. - Назначение: - @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 не взаимодействует ни с классом, ни с экземпляром. - Назначение: Позволяет управлять доступом к атрибутам класса,
Оглавление

В 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).