← Назад к вопросам

Какие знаешь встроенные декораторы?

1.0 Junior🔥 131 комментариев
#Python

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие знаешь встроенные декораторы Python?

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

1. @property

Превращает метод в свойство (атрибут).

class DataSet:
    def __init__(self, size):
        self._size = size
    
    @property
    def size(self):
        return self._size
    
    @size.setter
    def size(self, value):
        if value < 0:
            raise ValueError("Size must be positive")
        self._size = value

ds = DataSet(1000)
print(ds.size)  # Выглядит как атрибут
ds.size = 5000  # Валидация при присвоении

2. @staticmethod

Метод, который не требует доступа к self или cls.

class Math:
    @staticmethod
    def add(a, b):
        return a + b

result = Math.add(5, 3)  # 8

3. @classmethod

Метод получает доступ к cls (сам класс).

class Model:
    instances_count = 0
    
    def __init__(self, name):
        self.name = name
        Model.instances_count += 1
    
    @classmethod
    def get_count(cls):
        return cls.instances_count
    
    @classmethod
    def from_dict(cls, data):
        return cls(data['name'])

m1 = Model("M1")
print(Model.get_count())  # 1

4. @abstractmethod (из abc)

Определяет интерфейс для подклассов.

from abc import ABC, abstractmethod

class Estimator(ABC):
    @abstractmethod
    def fit(self, X, y):
        pass
    
    @abstractmethod
    def predict(self, X):
        pass

class MyModel(Estimator):
    def fit(self, X, y):
        pass
    
    def predict(self, X):
        pass

5. @lru_cache (из functools)

Кэширование результатов функции.

from functools import lru_cache

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

result = fibonacci(35)  # Быстро благодаря кэшу
print(fibonacci.cache_info())  # Смотреть статистику
fibonacci.cache_clear()  # Очистить кэш

6. @functools.wraps

Сохраняет метаданные оригинальной функции.

from functools import wraps

def my_decorator(func):
    @wraps(func)  # Копирует __name__, __doc__
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def add(a, b):
    "Adds two numbers"
    return a + b

print(add.__name__)  # 'add' (не 'wrapper'!)
print(add.__doc__)   # 'Adds two numbers'

7. @singledispatch (из functools)

Перегрузка функций в зависимости от типа аргумента.

from functools import singledispatch

@singledispatch
def process(arg):
    raise NotImplementedError(f"Cannot process {type(arg)}")

@process.register(int)
def _(arg):
    return arg * 2

@process.register(str)
def _(arg):
    return arg.upper()

@process.register(list)
def _(arg):
    return len(arg)

print(process(5))        # 10
print(process("hello"))  # HELLO
print(process([1, 2]))   # 2

8. Custom декоратор для ML

import time
from functools import wraps

def timing_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__}: {elapsed:.3f}s")
        return result
    return wrapper

@timing_decorator
def train_model(X, y):
    from sklearn.ensemble import GradientBoostingClassifier
    model = GradientBoostingClassifier(n_estimators=1000)
    model.fit(X, y)
    return model

Чек-лист при использовании декораторов

  • @wraps при создании собственных декораторов
  • @property для getter/setter логики
  • @classmethod для factory methods
  • @staticmethod для утилит
  • @abstractmethod для определения интерфейсов
  • @lru_cache только для pure functions (без побочных эффектов)
  • Не перегружай декораторами — код должен быть читаемым

Порядок применения декораторов

@decorator1  # Применяется вторым
@decorator2  # Применяется первым
def func():
    pass

# Эквивалент: func = decorator1(decorator2(func))
# Выполнение: decorator2 -> func -> decorator1